From 361a8aa4096fb772e65f6a48e264bd5bf123247e Mon Sep 17 00:00:00 2001 From: Sosthene Date: Thu, 15 Aug 2024 16:19:11 +0200 Subject: [PATCH 01/14] Update api --- src/api.rs | 143 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 51 deletions(-) diff --git a/src/api.rs b/src/api.rs index 257ff83..6f5ec06 100644 --- a/src/api.rs +++ b/src/api.rs @@ -23,6 +23,7 @@ use sdk_common::sp_client::bitcoin::hex::{ }; use sdk_common::sp_client::bitcoin::key::{Parity, Secp256k1}; use sdk_common::sp_client::bitcoin::network::ParseNetworkError; +use sdk_common::sp_client::bitcoin::p2p::message::NetworkMessage; use sdk_common::sp_client::bitcoin::psbt::raw; use sdk_common::sp_client::bitcoin::secp256k1::ecdh::shared_secret_point; use sdk_common::sp_client::bitcoin::secp256k1::{PublicKey, Scalar, SecretKey}; @@ -46,8 +47,7 @@ use wasm_bindgen::convert::FromWasmAbi; use wasm_bindgen::prelude::*; use sdk_common::network::{ - self, AnkFlag, AnkNetworkMsg, CachedMessage, CachedMessageStatus, CipherMessage, FaucetMessage, - NewTxMessage, + self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage, Pcd, Prd }; use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address}; @@ -570,7 +570,7 @@ fn handle_transaction( }) { let (outpoint, output) = utxo_created.into_iter().next().unwrap(); - let cipher_msg: CipherMessage = serde_json::from_slice(&plaintext)?; + let cipher_msg: Prd = serde_json::from_slice(&plaintext)?; message.commited_in = Some(outpoint.clone()); // freeze the commitment utxo let mut freezed_utxos = lock_freezed_utxos()?; @@ -578,8 +578,6 @@ fn handle_transaction( message.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); message.commitment = Some(commitment_str); - message.plaintext.push(cipher_msg.message); - message.ciphertext = None; message.sender = Some(cipher_msg.sender); message.recipient = Some(sp_wallet.get_client().get_receiving_address()); message.status = CachedMessageStatus::ReceivedMustConfirm; @@ -600,7 +598,7 @@ fn handle_transaction( new_msg.commitment = Some(commitment.to_lower_hex_string()); new_msg.recipient = Some(sp_wallet.get_client().get_receiving_address()); new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); - new_msg.status = CachedMessageStatus::TxWaitingCipher; + new_msg.status = CachedMessageStatus::TxWaitingPrd; messages.push(new_msg.clone()); return Ok(new_msg.clone()); } @@ -711,46 +709,62 @@ pub fn parse_cipher(cipher_msg: String, fee_rate: u32) -> ApiResult { - m.try_decrypt_cipher(cipher.clone()).is_ok() + CachedMessageStatus::TxWaitingPrd => { + m.try_decrypt_prd(cipher.clone()).is_ok() + } + CachedMessageStatus::GotPrdWaitingPcd => { + m.try_decrypt_pcd(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)?; + if message.status == CachedMessageStatus::TxWaitingPrd { + let plain = message.try_decrypt_prd(cipher).unwrap(); + debug!("Found message {}", String::from_utf8(plain.clone())?); + let prd: Prd = serde_json::from_slice(&plain)?; // does the retrieved message match with the commited hash? - let hash = create_commitment(serde_json::to_string(&cipher_msg)?); + let hash = create_commitment(serde_json::to_string(&prd)?); if Some(hash) != message.commitment { return Err(ApiError { - message: "Message doesn't match commitment".to_owned(), + message: "Prd doesn't match commitment".to_owned(), }); } - message.sender = Some(cipher_msg.sender); - message.ciphertext = None; - if cipher_msg.message.starts_with("PAIRING") { + message.sender = Some(prd.sender.clone()); + message.pcd_commitment = Some(prd.pcd_commitment.to_string()); + message.prd_cipher = None; + message.prd = Some(prd); + message.status = CachedMessageStatus::GotPrdWaitingPcd; + } else { + let plain = message.try_decrypt_pcd(cipher).unwrap(); + debug!("Found message {}", String::from_utf8(plain.clone())?); + // we're receiving a pcd for a prd we already have + let pcd: Pcd = serde_json::from_slice(&plain)?; + // check that the hash of the pcd is the same than commited in the prd + let pcd_commitment = create_commitment(pcd.to_string()); + if Some(&pcd_commitment) != message.pcd_commitment.as_ref() { + return Err(ApiError { + message: format!("Pcd doesn't match commitment: expected {:?}\ngot {}", message.pcd_commitment.as_ref(), pcd_commitment), + }); + } + + if pcd.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") { + } else if pcd.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)?); + message.pcd = Some(pcd); + message.pcd_cipher = None; } 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(cipher_msg); + new_msg.prd_cipher = Some(cipher_msg); messages.push(new_msg.clone()); return Ok(new_msg); } @@ -851,7 +865,7 @@ pub fn create_confirmation_transaction( let mut messages = lock_messages()?; let message: &mut CachedMessage; if let Some(m) = messages.iter_mut().find(|m| m.id == message_id) { - if m.sender.is_none() || m.commited_in.is_none() || m.plaintext.is_empty() { + if m.sender.is_none() || m.commited_in.is_none() || m.prd.is_none() { return Err(ApiError { message: "Invalid network message".to_owned(), }); @@ -938,19 +952,25 @@ pub fn create_login_transaction(fee_rate: u32) -> ApiResult ApiResult ApiResult ApiResult ApiResult { let sp_address: SilentPaymentAddress = address.as_str().try_into()?; @@ -1066,7 +1088,19 @@ pub fn create_notification_transaction( nb_outputs: 1, }; - let commitment = create_commitment(serde_json::to_string(&cipher_message)?); + let pcd_commitment = sha256sum(pcd.to_string().as_bytes()); + + let key: [u8; 32] = Aes256Gcm::generate_key(thread_rng()).into(); + + let prd = Prd::new( + sp_wallet.get_client().get_receiving_address().try_into().unwrap(), + key, + pcd_commitment + ); + + let prd_commitment = sha256sum(prd.to_string().as_bytes()); + + let pcd_cipher = prd.encrypt_pcd(&pcd)?; let freezed_utxos = lock_freezed_utxos()?; @@ -1075,7 +1109,7 @@ pub fn create_notification_transaction( &freezed_utxos, sp_wallet, vec![recipient], - Some(Vec::from_hex(&commitment)?), + Some(prd_commitment.as_byte_array().to_vec()), Amount::from_sat(fee_rate.into()), None, )?; @@ -1092,7 +1126,7 @@ pub fn create_notification_transaction( let shared_secret = AnkSharedSecret::new(shared_point); let cipher = encrypt_with_key( - serde_json::to_string(&cipher_message)?, + serde_json::to_string(&prd)?, shared_secret.to_byte_array().to_lower_hex_string(), )?; @@ -1105,16 +1139,19 @@ pub fn create_notification_transaction( // for now let's just take the smallest vout that belongs to the recipient let final_tx = signed_psbt.extract_tx()?; let mut new_msg = CachedMessage::new(); - new_msg.plaintext.push(cipher_message.message); - new_msg.ciphertext = Some(cipher); - new_msg.commitment = Some(commitment); + new_msg.sender = Some(prd.sender.clone()); + new_msg.prd = Some(prd); + new_msg.prd_cipher = Some(cipher); + new_msg.pcd = Some(pcd); + new_msg.pcd_cipher = Some(pcd_cipher.to_lower_hex_string()); + + new_msg.commitment = Some(prd_commitment.as_byte_array().to_lower_hex_string()); new_msg.commited_in = Some(OutPoint { txid: final_tx.txid(), vout: recipients_vouts[0] as u32, }); new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); new_msg.recipient = Some(address); - new_msg.sender = Some(cipher_message.sender); new_msg.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself new_msg.status = CachedMessageStatus::SentWaitingConfirmation; lock_messages()?.push(new_msg.clone()); @@ -1209,15 +1246,19 @@ pub fn create_faucet_msg() -> ApiResult { cached_msg.status = CachedMessageStatus::FaucetWaiting; lock_messages()?.push(cached_msg.clone()); - let network_msg = AnkNetworkMsg::new(AnkFlag::Faucet, &faucet_msg.to_string()); + let network_msg = Envelope::new(AnkFlag::Faucet, &faucet_msg.to_string()); Ok(network_msg.to_string()) } +fn sha256sum(input: &[u8]) -> sha256::Hash { + let mut engine = sha256::HashEngine::default(); + engine.write_all(&input); + sha256::Hash::from_engine(engine) +} + #[wasm_bindgen] pub fn create_commitment(payload_to_hash: String) -> String { - let mut engine = sha256::HashEngine::default(); - engine.write_all(&payload_to_hash.as_bytes()); - let hash = sha256::Hash::from_engine(engine); + let hash = sha256sum(payload_to_hash.as_bytes()); hash.to_byte_array().to_lower_hex_string() } From d073b12340dafd0e3e0dcefd3a75352b4ab65673 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Thu, 15 Aug 2024 16:19:29 +0200 Subject: [PATCH 02/14] Update tests --- tests/browser.rs | 550 --------------------------------------------- tests/challenge.rs | 153 +++++++++++++ tests/pairing.rs | 248 ++++++++++++++++++++ tests/prd.rs | 67 ++++++ tests/utils.rs | 107 +++++++++ 5 files changed, 575 insertions(+), 550 deletions(-) delete mode 100644 tests/browser.rs create mode 100644 tests/challenge.rs create mode 100644 tests/pairing.rs create mode 100644 tests/prd.rs create mode 100644 tests/utils.rs diff --git a/tests/browser.rs b/tests/browser.rs deleted file mode 100644 index 412b0e8..0000000 --- a/tests/browser.rs +++ /dev/null @@ -1,550 +0,0 @@ -use std::collections::HashMap; - -use log::debug; -use sdk_client::api::{ - answer_confirmation_transaction, create_confirmation_transaction, create_login_transaction, create_notification_transaction, create_pairing_transaction, dump_device, dump_message_cache, dump_wallet, encrypt_with_key, encrypt_with_new_key, get_outputs, login, pair_device, parse_network_msg, reset_device, reset_message_cache, restore_device, restore_device_from_sp_wallet, set_message_cache, setup -}; -use sdk_common::network::{ - AnkNetworkMsg, CachedMessage, CachedMessageStatus, CipherMessage, NewTxMessage, TrustedChannel, -}; -use sdk_common::sp_client::bitcoin::consensus::deserialize; -use sdk_common::sp_client::bitcoin::hex::FromHex; -use sdk_common::sp_client::bitcoin::secp256k1::PublicKey; -use sdk_common::sp_client::bitcoin::{OutPoint, ScriptBuf, Transaction}; -use sdk_common::sp_client::silentpayments::utils::receiving::{ - calculate_tweak_data, get_pubkey_from_input, -}; -use sdk_common::sp_client::spclient::{OutputSpendStatus, OwnedOutput, SpWallet}; -use serde_json; - -use tsify::JsValueSerdeExt; -use wasm_bindgen_test::*; - -wasm_bindgen_test_configure!(run_in_browser); - -// We're using alice and bob for clarity, but it's important to remember that for pairing and login Alice and Bob are the same person -const ALICE_START_WALLET: &str = "{\"client\":{\"network\":\"regtest\",\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]}},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; -const ALICE_LOGIN_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}}}},\"tx_history\":[]}"; -const BOB_START_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; -const BOB_LOGIN_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; -const BOB_PAIRED_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a\"}},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a\"}},\"e34824b0de3f00416caf295dd919fd695404c34334a36b9e7b81917c64fc9701:0\":{\"blockheight\":0,\"tweak\":\"49ab242529118b90ee3db481f7f979588bea59abaf71f6fdb1326156ec95d1f9\",\"amount\":1200,\"script\":\"51204d4dafb5ba432c6ecffc2db7965c901b20312e1beb08132ef9893073e0cbb1bd\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a:1\":{\"blockheight\":0,\"tweak\":\"70265572d5f239fb96022c48c49ba73dc0c544cfe4a2a77900aae12476258e7c\",\"amount\":191,\"script\":\"5120e3c9e3a1a606214c0b2138efe90bf394a92f3210062899ad11e58b35dbf12d9d\",\"label\":null,\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a\"}},\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a:2\":{\"blockheight\":0,\"tweak\":\"dc37abf37053e241d71f6c401b056d8e6f944f06811daa18494387001f20faed\",\"amount\":99895946,\"script\":\"512050de7190c8b7dd4d6268e716f89a9be001674b8779574bed42be53fa02531c68\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; -const ALICE_SPK: &str = "51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1"; -const REVOKATION_OUTPUT: &str = - "3dd51588af6cc2e4ff8e405fd2620f19c8f4e09e05692ad57a9208a061687295:3"; -const ALICE_ANSWER_CACHE: &str = "[{\"id\":1436790358,\"status\":\"MustSpendConfirmation\",\"ciphertext\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590537,\"error\":null}]"; -const ALICE_FINAL_CACHE: &str = "[{\"id\":1436790358,\"status\":\"Trusted\",\"ciphertext\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590537,\"error\":null}]"; -const BOB_ANSWER_CACHE: &str = "[{\"id\":2887008190,\"status\":\"ReceivedMustConfirm\",\"ciphertext\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590605,\"error\":null}]"; -const BOB_FINAL_CACHE: &str = "[{\"id\":2887008190,\"status\":\"Trusted\",\"ciphertext\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590605,\"error\":null}]"; - -const BOB_PAIRING_CACHE: &str = "[{\"id\":2853916441,\"status\":\"Pairing\",\"ciphertext\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\",\"tied_by\":null,\"commitment\":\"7f340cd5f070a4bd8d16077214a0488e43bd41d64d8b2b39ab0fc016c1093eba\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"a86c30250a8e6a8dc9581b3ab2dacafda6446f6c65f4debe124f5870b6796ea1\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062445,\"error\":null}, {\"id\":1045548533,\"status\":\"Closed\",\"ciphertext\":\"bd2acbc73fc402a8cb57121153f2667b944fe31f67ccdd6031e7d9481642f42ebdae00b572b1be6735ff413ceedccf29d2f0700021c6cf61b954891912968a449e6cb735e9344d90db21268ff596f844db358bc4852358ac89a71e81179b249b499a6b70bef341ff71737ea0a9a7e3f2a90bb41d376272410a18ec367d5b6f417420d6d6ee06a132c263269cba281c1fa6e644b5beed716783e973594f5e9da76c28bdc10968ec7e49031924fb8051ec80d27f87e943f884263cb1a273b18f79\",\"plaintext\":[\"PAIRING\"],\"commited_in\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\",\"tied_by\":1,\"commitment\":\"213c1295d6721f3194745063190487e73853c21373218255d2af20c4b1ba6a7b\",\"sender\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"recipient\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"shared_secret\":\"094849bcf340d0791fa0bae31c9b58b8572ad3c9bd028de3a26e501b578cb24b\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062534,\"error\":null}]"; -const ALICE_PAIRING_CACHE: &str = "[{\"id\":2059106889,\"status\":\"Closed\",\"ciphertext\":\"6634050737f9dc18b187c69872943f9a11764252bac9e163fcb7480fd0aa3cf543f7b0b7eef9579d1ddba0b79fdf8c59747050313d0518ea4c8d23d2665948549efd72d0fde7bc8e7a02936de78b7406a31072429d9a81751d5665e9333f8c429c59e47a11b8993583fc5806c8e8695db970247761d11782188c550bd19f7a2c60172104c2892a463f79c19e4173852279012003edf3f777e7c1a95e7d87863d155bcaee1fc4c1b0cb69cab42a45ad5c6271a9c9ba4f79e49a3de2e0fa0aa9bc\",\"plaintext\":[\"PAIRING\"],\"commited_in\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\",\"tied_by\":1,\"commitment\":\"7f340cd5f070a4bd8d16077214a0488e43bd41d64d8b2b39ab0fc016c1093eba\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"a86c30250a8e6a8dc9581b3ab2dacafda6446f6c65f4debe124f5870b6796ea1\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062375,\"error\":null}, {\"id\":3841225687,\"status\":\"Pairing\",\"ciphertext\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\",\"tied_by\":null,\"commitment\":\"213c1295d6721f3194745063190487e73853c21373218255d2af20c4b1ba6a7b\",\"sender\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"recipient\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"shared_secret\":\"094849bcf340d0791fa0bae31c9b58b8572ad3c9bd028de3a26e501b578cb24b\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062605,\"error\":null}]"; - -const ALICE_CHALLENGE_CACHE: &str = "[{\"id\":1436790358,\"status\":\"SentWaitingConfirmation\",\"ciphertext\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1723198590537,\"error\":null}]"; -const BOB_CHALLENGE_CACHE: &str = "[{\"id\":2887008190,\"status\":\"ReceivedMustConfirm\",\"ciphertext\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1723198590605,\"error\":null}]"; - -const ALICE_PAIRED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\"}}"; -const BOB_PAIRED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\"}}"; - -const ALICE_LOGGED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; -const BOB_LOGGED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; - -const ALICE_CHALLENGE_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; -const BOB_CHALLENGE_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\":{\"blockheight\":0,\"tweak\":\"21fc32bded971dd15387671436232f17d932e18758f69b476219e2d6e688767f\",\"amount\":1200,\"script\":\"5120230d06322d10a5838634df3c55eef9959a1c0c144108e0416b9687eaf22e6baa\",\"label\":null,\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; - -const ALICE_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":\"Unspent\"},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\":{\"blockheight\":0,\"tweak\":\"de507c854cee16d2e157fbf6c6dbfd2e721b861efc7f657bb724790fc7829665\",\"amount\":349,\"script\":\"5120028143243ed5d4554e60d96ee61fdf6f6e359a9083311c210645c0a7fef51248\",\"label\":null,\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; -const BOB_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:1\":{\"blockheight\":0,\"tweak\":\"281ea54f74e5f6582a7462bdd9397b9a786f97455e858e7901a6a4fa95f39192\",\"amount\":654,\"script\":\"5120aa4395e2be9cbce580e94f4308d64422da251b7df12fb8c571675d40cc50cf00\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\":{\"blockheight\":0,\"tweak\":\"21fc32bded971dd15387671436232f17d932e18758f69b476219e2d6e688767f\",\"amount\":1200,\"script\":\"5120230d06322d10a5838634df3c55eef9959a1c0c144108e0416b9687eaf22e6baa\",\"label\":null,\"spend_status\":{\"Spent\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; - -const ALICE_FINAL_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\":{\"blockheight\":0,\"tweak\":\"de507c854cee16d2e157fbf6c6dbfd2e721b861efc7f657bb724790fc7829665\",\"amount\":349,\"script\":\"5120028143243ed5d4554e60d96ee61fdf6f6e359a9083311c210645c0a7fef51248\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; -const BOB_FINAL_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\":{\"blockheight\":0,\"tweak\":\"21fc32bded971dd15387671436232f17d932e18758f69b476219e2d6e688767f\",\"amount\":1200,\"script\":\"5120230d06322d10a5838634df3c55eef9959a1c0c144108e0416b9687eaf22e6baa\",\"label\":null,\"spend_status\":{\"Spent\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d\"}},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:1\":{\"blockheight\":0,\"tweak\":\"281ea54f74e5f6582a7462bdd9397b9a786f97455e858e7901a6a4fa95f39192\",\"amount\":654,\"script\":\"5120aa4395e2be9cbce580e94f4308d64422da251b7df12fb8c571675d40cc50cf00\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308:0\":{\"blockheight\":0,\"tweak\":\"ef47f5ff1081b30725e1954a1f0df9b3785378be5ed4aa9542c77cad55a4265f\",\"amount\":385,\"script\":\"51205500d79439795bf164bebd259f1d4a00d172f9e68a4dd42a64830e8c99d2988f\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; - -fn helper_switch_device(wallet: String) { - reset_device().unwrap(); - restore_device_from_sp_wallet(wallet.clone()).unwrap(); -} - -fn helper_get_alice_address() -> String { - let wallet: SpWallet = serde_json::from_str(ALICE_START_WALLET).unwrap(); - wallet.get_client().get_receiving_address() -} - -fn helper_get_bob_address() -> String { - let wallet: SpWallet = serde_json::from_str(BOB_START_WALLET).unwrap(); - wallet.get_client().get_receiving_address() -} - -fn helper_get_tweak_data(transaction: &str, outpoints: HashMap) -> String { - let tx = deserialize::(&Vec::from_hex(transaction).unwrap()).unwrap(); - let mut outpoint_data = vec![]; - let mut witnesses = vec![]; - let mut spks = vec![]; - for prevout in tx.input { - outpoint_data.push(( - prevout.previous_output.txid.to_string(), - prevout.previous_output.vout, - )); - witnesses.push(prevout.witness); - if let Some(output) = outpoints.get(&prevout.previous_output) { - spks.push(ScriptBuf::from_hex(&output.script).unwrap()); - } - } - let mut input_pubkeys = vec![]; - for (spk, witness) in spks.iter().zip(witnesses) { - let input_pubkey = - get_pubkey_from_input(&vec![], &witness.to_vec(), spk.as_bytes()).unwrap(); - input_pubkeys.push(input_pubkey.unwrap()); - } - let ref_pubkeys: Vec<&PublicKey> = input_pubkeys.iter().collect(); - let tweak_data = calculate_tweak_data(&ref_pubkeys, &outpoint_data).unwrap(); - tweak_data.to_string() -} - -fn helper_parse_transaction(transaction: &str, tweak_data: &str) -> CachedMessage { - let new_tx_msg = serde_json::to_string(&NewTxMessage::new( - transaction.to_owned(), - Some(tweak_data.to_owned()), - )) - .unwrap(); - let network_msg = serde_json::to_string(&AnkNetworkMsg::new( - sdk_common::network::AnkFlag::NewTx, - &new_tx_msg, - )) - .unwrap(); - let result = parse_network_msg(network_msg, 1); - match result { - Ok(m) => m, - Err(e) => panic!("Unexpected error: {}", e.message), - } -} - -fn helper_parse_ank_msg(ank_network_msg: String) -> CachedMessage { - let result = parse_network_msg(ank_network_msg, 1); - match result { - Ok(r) => return r, - Err(e) => panic!("Unexpected error: {}", e.message), - }; -} - -#[wasm_bindgen_test] -fn test_pairing() { - setup(); - debug!("==============================================\nStarting test_pairing\n=============================================="); - - // ========================= Alice - helper_switch_device(ALICE_LOGIN_WALLET.to_owned()); - - debug!("Alice sends a pairing transaction to Bob"); - let alice_pairing_tx = create_pairing_transaction(helper_get_bob_address(), 1).unwrap(); - - debug!("Alice pairing tx: {}", alice_pairing_tx.txid); - - // This is sent on 4nk network along with the transaction - let alice_pairing_cipher = AnkNetworkMsg::new( - sdk_common::network::AnkFlag::Cipher, - &alice_pairing_tx.new_network_msg.ciphertext.unwrap(), - ); - - let get_outputs_result = get_outputs().unwrap(); - - let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let alice_pairing_tweak_data = - helper_get_tweak_data(&alice_pairing_tx.transaction, alice_outputs); - - // Alice parse her own transaction - let alice_msg_id = - helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data).id; - - let alice_wallet = dump_wallet().unwrap(); - let alice_cache = dump_message_cache().unwrap(); - - // ======================= Bob - reset_device().unwrap(); - helper_switch_device(BOB_LOGIN_WALLET.to_owned()); - - // Bob receives Alice pairing transaction - // if he agrees, he must send another pairing transaction to Alice - // he can also spend the output that notified him that will become Alice first session key - debug!("Bob parses Alice pairing transaction"); - helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data); - let alice_pairing_res = helper_parse_ank_msg(alice_pairing_cipher.to_string()); - - assert!(alice_pairing_res.status == CachedMessageStatus::Pairing); - - // Bob takes the txid of the incoming transaction from Alice, he will need it for pairing - let incoming_txid = alice_pairing_res.commited_in.unwrap().txid; - - // At this point, user must validate the pairing proposal received from Alice - - debug!("Bob sends a pairing transaction back"); - let bob_pairing_tx = create_pairing_transaction(alice_pairing_res.sender.unwrap(), 1).unwrap(); - - let bob_pairing_cipher = AnkNetworkMsg::new( - sdk_common::network::AnkFlag::Cipher, - &bob_pairing_tx.new_network_msg.ciphertext.unwrap(), - ); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let bob_pairing_tweak_data = helper_get_tweak_data(&bob_pairing_tx.transaction, bob_outputs); - - helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); - - debug!("Bob pairs device with Alice"); - pair_device(bob_pairing_tx.new_network_msg.id, incoming_txid.to_string()).unwrap(); - - // ======================== Alice - reset_device().unwrap(); - helper_switch_device(alice_wallet); - set_message_cache(alice_cache).unwrap(); - - // parse Bob's pairing transaction - helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); - let bob_pairing_msg = helper_parse_ank_msg(bob_pairing_cipher.to_string()); - - assert!(bob_pairing_msg.status == CachedMessageStatus::Pairing); - - debug!("Alice pairs device"); - pair_device(alice_msg_id, bob_pairing_tx.txid).unwrap(); -} - -#[wasm_bindgen_test] -fn test_first_login() { - reset_device().unwrap(); - setup(); - debug!("==============================================\nStarting test_first_login\n=============================================="); - - restore_device(BOB_PAIRED_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(BOB_PAIRING_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - // Bob can now spend the notification output, that will become Alice's first session key - debug!("Bob first login"); - let bob_first_login_tx = create_login_transaction(1).unwrap(); - let bob_login_cipher = AnkNetworkMsg::new( - sdk_common::network::AnkFlag::Cipher, - &bob_first_login_tx.new_network_msg.ciphertext.unwrap(), - ); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let bob_login_tweak_data = helper_get_tweak_data(&bob_first_login_tx.transaction, bob_outputs); - - debug!("Bob parses his own login transaction"); - helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data); - - let bob_device = dump_device().unwrap(); - let bob_cache = dump_message_cache().unwrap(); - - // ======================== Alice - reset_device().unwrap(); - restore_device(ALICE_PAIRED_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(ALICE_PAIRING_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - debug!("Alice finds out the login demand from Bob"); - helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data); - let bob_login_msg = helper_parse_ank_msg(bob_login_cipher.to_string()); - - // At this point Alice can fire up the revokation output if the login demand is illegitimate - // OR she must answer with a login transaction to Bob - debug!("Alice first login"); - let alice_first_login_tx = create_login_transaction(1).unwrap(); - let alice_login_cipher = AnkNetworkMsg::new( - sdk_common::network::AnkFlag::Cipher, - &alice_first_login_tx.new_network_msg.ciphertext.unwrap(), - ); - - let get_outputs_result = get_outputs().unwrap(); - - let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let alice_login_tweak_data = - helper_get_tweak_data(&alice_first_login_tx.transaction, alice_outputs); - - helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data); - - login(bob_login_msg.id, alice_first_login_tx.transaction.clone()).unwrap(); - - // ======================= Bob - reset_device().unwrap(); - restore_device(bob_device).unwrap(); - set_message_cache(bob_cache).unwrap(); - - helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data); - let alice_login_msg = helper_parse_ank_msg(alice_login_cipher.to_string()); - - assert!(alice_login_msg.status == CachedMessageStatus::Login); - - login(alice_login_msg.id, bob_first_login_tx.transaction).unwrap(); -} - -#[wasm_bindgen_test] -fn test_login() { - reset_device().unwrap(); - setup(); - debug!("==============================================\nStarting test_login\n=============================================="); - - // ======================= Alice - restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap(); - - debug!("Alice sends a login transaction to Bob, which creates a new key for him"); - let alice_login_tx = create_login_transaction(1).unwrap(); - let alice_login_cipher = AnkNetworkMsg::new( - sdk_common::network::AnkFlag::Cipher, - &alice_login_tx.new_network_msg.ciphertext.unwrap(), - ); - - let get_outputs_result = get_outputs().unwrap(); - - let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let alice_login_tweak_data = helper_get_tweak_data( - &alice_login_tx.transaction, - alice_outputs - ); - - debug!("Parsing Alice login transaction"); - helper_parse_transaction(&alice_login_tx.transaction, &alice_login_tweak_data); - - let alice_device = dump_device().unwrap(); - let alice_cache = dump_message_cache().unwrap(); - - // ============================== Bob - reset_device().unwrap(); - restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap(); - - debug!("Bob finds out the login demand from Alice"); - helper_parse_transaction(&alice_login_tx.transaction, &alice_login_tweak_data); - let alice_login_msg = helper_parse_ank_msg(alice_login_cipher.to_string()); - - // Bob must confirm that he agrees to log in - - // Boutons "login" ou "Refuser" - // At this point Bob can fire up the revokation output if the login demand is illegitimate - // revoke_paired_device(1).unwrap(); - // OR it must answer with a login transaction to Alice - let bob_login_tx = create_login_transaction(1).unwrap(); - let bob_login_cipher = AnkNetworkMsg::new( - sdk_common::network::AnkFlag::Cipher, - &bob_login_tx.new_network_msg.ciphertext.unwrap(), - ); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let bob_login_tweak_data = helper_get_tweak_data(&bob_login_tx.transaction, bob_outputs); - - debug!("Bob parses his own login transaction"); - helper_parse_transaction(&bob_login_tx.transaction, &bob_login_tweak_data); - - login(alice_login_msg.id, alice_login_tx.transaction.clone()).unwrap(); - - // =================== Alice - - reset_device().unwrap(); - restore_device(alice_device).unwrap(); - set_message_cache(alice_cache).unwrap(); - - helper_parse_transaction(&bob_login_tx.transaction, &bob_login_tweak_data); - let bob_login_msg = helper_parse_ank_msg(bob_login_cipher.to_string()); - - assert!(bob_login_msg.status == CachedMessageStatus::Login); - - login(bob_login_msg.id, alice_login_tx.transaction).unwrap(); -} - -#[wasm_bindgen_test] -fn test_alice_notifies_bob() { - reset_device().unwrap(); - setup(); - debug!("==============================================\nStarting test_alice_notifies_bob\n=============================================="); - - // ============================ Alice - restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap(); - - debug!("Alice notified Bob about a message she sent to it"); - - let cipher_msg = CipherMessage::new(helper_get_alice_address(), "TEST".to_owned()); - let notification_tx = - create_notification_transaction(helper_get_bob_address(), cipher_msg, 1).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - let notification_tweak_data = helper_get_tweak_data( - ¬ification_tx.transaction, - alice_outputs - ); - - let ank_msg = AnkNetworkMsg::new( - sdk_common::network::AnkFlag::Cipher, - ¬ification_tx.new_network_msg.ciphertext.unwrap(), - ); - - debug!("Alice parse her own notification transaction"); - // Alice parse her own transaction to update her utxos - helper_parse_transaction( - ¬ification_tx.transaction, - ¬ification_tweak_data, - ); - - reset_device().unwrap(); - restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap(); - - debug!( - "Bob parses notification transaction {}", - notification_tx.txid - ); - // bob parses the transaction and the message - helper_parse_transaction(¬ification_tx.transaction, ¬ification_tweak_data); - helper_parse_ank_msg(ank_msg.to_string()); -} - -#[wasm_bindgen_test] -fn test_bob_challenges_alice() { - reset_device().unwrap(); - debug!("==============================================\nStarting test_bob_challenges_alice\n=============================================="); - - // =============================== Bob - setup(); - restore_device(BOB_CHALLENGE_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(BOB_CHALLENGE_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - let notification_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - debug!("Bob sends a challenge transaction back to Alice"); - let confirmation_tx = create_confirmation_transaction(notification_msg.id, 1).unwrap(); - - let confirmation_tweak_data = helper_get_tweak_data( - &confirmation_tx.transaction, - bob_outputs - ); - - debug!("Bob parsing its own confirmation tx"); - helper_parse_transaction( - &confirmation_tx.transaction, - &confirmation_tweak_data, - ); - - // ========================== Alice - reset_device().unwrap(); - restore_device(ALICE_CHALLENGE_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(ALICE_CHALLENGE_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - debug!("Alice parsing confirmation tx"); - helper_parse_transaction(&confirmation_tx.transaction, &confirmation_tweak_data); -} - -#[wasm_bindgen_test] -fn test_alice_answers_bob() { - reset_device().unwrap(); - setup(); - debug!("==============================================\nStarting test_alice_answers_bob\n=============================================="); - restore_device(ALICE_ANSWER_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(ALICE_ANSWER_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - let challenge_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); - - debug!("Alice answers bob's challenge"); - let answer_tx = answer_confirmation_transaction(challenge_msg.id, 1).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let answer_tweak_data = helper_get_tweak_data( - &answer_tx.transaction, - alice_outputs, - ); - - debug!("Alice parses her own transaction"); - helper_parse_transaction(&answer_tx.transaction, &answer_tweak_data); - - reset_device().unwrap(); - restore_device(BOB_ANSWER_DEVICE.to_owned()).unwrap(); - - set_message_cache( - serde_json::from_str::>(BOB_ANSWER_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - debug!("Bob parses answer transaction {}", answer_tx.txid); - let answer_msg = helper_parse_transaction(&answer_tx.transaction, &answer_tweak_data); -} - -#[wasm_bindgen_test] -fn test_alice_sends_message_through_trusted_channel() { - reset_device().unwrap(); - setup(); - debug!("==============================================\nStarting test_alice_sends_message_through_trusted_channel\n=============================================="); - - restore_device(ALICE_FINAL_DEVICE.to_owned()).unwrap(); - - set_message_cache( - serde_json::from_str::>(ALICE_FINAL_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - let answered_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); - - // Bob sends a message to Alice - debug!("Bob Sends a message to Alice"); - let secret_msg = "Hello Alice"; - let cipher = - encrypt_with_key(secret_msg.to_owned(), answered_msg.shared_secret.unwrap()).unwrap(); - let bob_msg = AnkNetworkMsg::new(sdk_common::network::AnkFlag::Cipher, &cipher); - - // Alice can find the message - let mut result = helper_parse_ank_msg(bob_msg.to_string()); - assert!(result.plaintext.pop() == Some(secret_msg.to_owned())); -} diff --git a/tests/challenge.rs b/tests/challenge.rs new file mode 100644 index 0000000..5750aa2 --- /dev/null +++ b/tests/challenge.rs @@ -0,0 +1,153 @@ +use std::collections::HashMap; + +use log::debug; +use sdk_client::api::{ + create_confirmation_transaction, create_notification_transaction, dump_device, dump_message_cache, get_outputs, reset_device, restore_device, set_message_cache, setup +}; +use sdk_common::network::{ + CachedMessage, CachedMessageStatus, Pcd +}; +use sdk_common::sp_client::bitcoin::OutPoint; +use sdk_common::sp_client::spclient::OwnedOutput; + +use tsify::JsValueSerdeExt; +use wasm_bindgen_test::*; + +wasm_bindgen_test_configure!(run_in_browser); + +mod utils; + +use utils::*; + +#[wasm_bindgen_test] +fn test_bob_challenges_alice() { + reset_device().unwrap(); + debug!("==============================================\nStarting test_bob_challenges_alice\n=============================================="); + + // =============================== Bob + setup(); + restore_device(BOB_CHALLENGE_DEVICE.to_owned()).unwrap(); + set_message_cache( + serde_json::from_str::>(BOB_CHALLENGE_CACHE) + .unwrap() + .into_iter() + .map(|v| v.to_string()) + .collect(), + ) + .unwrap(); + + let notification_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + debug!("Bob sends a challenge transaction back to Alice"); + debug!("outpoints: {:?}", bob_outputs); + let confirmation_tx = create_confirmation_transaction(notification_msg.id, 1).unwrap(); + + let confirmation_tweak_data = helper_get_tweak_data( + &confirmation_tx.transaction, + bob_outputs + ); + + debug!("Bob parsing its own confirmation tx"); + helper_parse_transaction( + &confirmation_tx.transaction, + &confirmation_tweak_data, + ); + + // ========================== Alice + reset_device().unwrap(); + restore_device(ALICE_CHALLENGE_DEVICE.to_owned()).unwrap(); + set_message_cache( + serde_json::from_str::>(ALICE_CHALLENGE_CACHE) + .unwrap() + .into_iter() + .map(|v| v.to_string()) + .collect(), + ) + .unwrap(); + + debug!("Alice parsing confirmation tx"); + helper_parse_transaction(&confirmation_tx.transaction, &confirmation_tweak_data); +} + +// #[wasm_bindgen_test] +// fn test_alice_answers_bob() { +// reset_device().unwrap(); +// setup(); +// debug!("==============================================\nStarting test_alice_answers_bob\n=============================================="); +// restore_device(ALICE_ANSWER_DEVICE.to_owned()).unwrap(); +// set_message_cache( +// serde_json::from_str::>(ALICE_ANSWER_CACHE) +// .unwrap() +// .into_iter() +// .map(|v| v.to_string()) +// .collect(), +// ) +// .unwrap(); + +// let challenge_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); + +// debug!("Alice answers bob's challenge"); +// let answer_tx = answer_confirmation_transaction(challenge_msg.id, 1).unwrap(); + +// let get_outputs_result = get_outputs().unwrap(); + +// let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + +// let answer_tweak_data = helper_get_tweak_data( +// &answer_tx.transaction, +// alice_outputs, +// ); + +// debug!("Alice parses her own transaction"); +// helper_parse_transaction(&answer_tx.transaction, &answer_tweak_data); + +// reset_device().unwrap(); +// restore_device(BOB_ANSWER_DEVICE.to_owned()).unwrap(); + +// set_message_cache( +// serde_json::from_str::>(BOB_ANSWER_CACHE) +// .unwrap() +// .into_iter() +// .map(|v| v.to_string()) +// .collect(), +// ) +// .unwrap(); + +// debug!("Bob parses answer transaction {}", answer_tx.txid); +// helper_parse_transaction(&answer_tx.transaction, &answer_tweak_data); +// } + +// #[wasm_bindgen_test] +// fn test_alice_sends_message_through_trusted_channel() { +// reset_device().unwrap(); +// setup(); +// debug!("==============================================\nStarting test_alice_sends_message_through_trusted_channel\n=============================================="); + +// restore_device(ALICE_FINAL_DEVICE.to_owned()).unwrap(); + +// set_message_cache( +// serde_json::from_str::>(ALICE_FINAL_CACHE) +// .unwrap() +// .into_iter() +// .map(|v| v.to_string()) +// .collect(), +// ) +// .unwrap(); + +// let answered_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); + +// // Bob sends a message to Alice +// debug!("Bob Sends a message to Alice"); +// let secret_msg = "Hello Alice"; +// let cipher = +// encrypt_with_key(secret_msg.to_owned(), answered_msg.shared_secret.unwrap()).unwrap(); +// let bob_msg = Envelope::new(sdk_common::network::AnkFlag::Cipher, &cipher); + +// // Alice can find the message +// let mut result = helper_parse_cipher(bob_msg.to_string()); +// assert!(result.plaintext.pop() == Some(secret_msg.to_owned())); +// } \ No newline at end of file diff --git a/tests/pairing.rs b/tests/pairing.rs new file mode 100644 index 0000000..2543070 --- /dev/null +++ b/tests/pairing.rs @@ -0,0 +1,248 @@ +use std::collections::HashMap; + +use log::debug; +use sdk_client::api::{ + create_login_transaction, create_pairing_transaction, dump_device, dump_message_cache, dump_wallet, get_outputs, login, pair_device, reset_device, restore_device, set_message_cache, setup +}; +use sdk_common::network::{ + CachedMessage, CachedMessageStatus, +}; +use sdk_common::sp_client::bitcoin::OutPoint; +use sdk_common::sp_client::spclient::OwnedOutput; +use serde_json; + +use tsify::JsValueSerdeExt; +use wasm_bindgen_test::*; + +mod utils; + +use utils::*; + +wasm_bindgen_test_configure!(run_in_browser); + +#[wasm_bindgen_test] +fn test_pairing() { + setup(); + debug!("==============================================\nStarting test_pairing\n=============================================="); + + // ========================= Alice + helper_switch_device(ALICE_LOGIN_WALLET.to_owned()); + + debug!("Alice sends a pairing transaction to Bob"); + let alice_pairing_tx = create_pairing_transaction(helper_get_bob_address(), 1).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let alice_pairing_tweak_data = + helper_get_tweak_data(&alice_pairing_tx.transaction, alice_outputs); + + // Alice parse her own transaction + let alice_msg_id = + helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data).id; + + let alice_wallet = dump_wallet().unwrap(); + let alice_cache = dump_message_cache().unwrap(); + + // ======================= Bob + reset_device().unwrap(); + helper_switch_device(BOB_LOGIN_WALLET.to_owned()); + + // Bob receives Alice pairing transaction + // if he agrees, he must send another pairing transaction to Alice + // he can also spend the output that notified him that will become Alice first session key + debug!("Bob parses Alice pairing transaction"); + helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data); + + debug!("Bob receives the prd"); + helper_parse_cipher(alice_pairing_tx.new_network_msg.prd_cipher.unwrap()); + + debug!("Bob receives the pcd"); + let alice_pairing_res = helper_parse_cipher(alice_pairing_tx.new_network_msg.pcd_cipher.unwrap()); + + assert!(alice_pairing_res.status == CachedMessageStatus::Pairing); + // Bob takes the txid of the incoming transaction from Alice, he will need it for pairing + let incoming_txid = alice_pairing_res.commited_in.unwrap().txid; + + // At this point, user must validate the pairing proposal received from Alice + + debug!("Bob sends a pairing transaction back"); + let bob_pairing_tx = create_pairing_transaction(alice_pairing_res.sender.unwrap(), 1).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let bob_pairing_tweak_data = helper_get_tweak_data(&bob_pairing_tx.transaction, bob_outputs); + + helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); + + debug!("Bob pairs device with Alice"); + pair_device(bob_pairing_tx.new_network_msg.id, incoming_txid.to_string()).unwrap(); + + // ======================== Alice + reset_device().unwrap(); + helper_switch_device(alice_wallet); + set_message_cache(alice_cache).unwrap(); + + // parse Bob's pairing transaction + helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); + helper_parse_cipher(bob_pairing_tx.new_network_msg.prd_cipher.unwrap()); + + let bob_pairing_msg = helper_parse_cipher(bob_pairing_tx.new_network_msg.pcd_cipher.unwrap()); + + assert!(bob_pairing_msg.status == CachedMessageStatus::Pairing); + + debug!("Alice pairs device"); + pair_device(alice_msg_id, bob_pairing_tx.txid).unwrap(); +} + +#[wasm_bindgen_test] +fn test_first_login() { + reset_device().unwrap(); + setup(); + debug!("==============================================\nStarting test_first_login\n=============================================="); + + restore_device(BOB_PAIRED_DEVICE.to_owned()).unwrap(); + set_message_cache( + serde_json::from_str::>(BOB_PAIRING_CACHE) + .unwrap() + .into_iter() + .map(|v| v.to_string()) + .collect(), + ) + .unwrap(); + + // Bob can now spend the notification output, that will become Alice's first session key + debug!("Bob first login"); + let bob_first_login_tx = create_login_transaction(1).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let bob_login_tweak_data = helper_get_tweak_data(&bob_first_login_tx.transaction, bob_outputs); + + debug!("Bob parses his own login transaction"); + helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data); + + let bob_device = dump_device().unwrap(); + let bob_cache = dump_message_cache().unwrap(); + + // ======================== Alice + reset_device().unwrap(); + restore_device(ALICE_PAIRED_DEVICE.to_owned()).unwrap(); + set_message_cache( + serde_json::from_str::>(ALICE_PAIRING_CACHE) + .unwrap() + .into_iter() + .map(|v| v.to_string()) + .collect(), + ) + .unwrap(); + + debug!("Alice finds out the login demand from Bob"); + helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data); + helper_parse_cipher(bob_first_login_tx.new_network_msg.prd_cipher.unwrap()); + let bob_login_msg = helper_parse_cipher(bob_first_login_tx.new_network_msg.pcd_cipher.unwrap()); + + // At this point Alice can fire up the revokation output if the login demand is illegitimate + // OR she must answer with a login transaction to Bob + debug!("Alice first login"); + let alice_first_login_tx = create_login_transaction(1).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let alice_login_tweak_data = + helper_get_tweak_data(&alice_first_login_tx.transaction, alice_outputs); + + helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data); + + login(bob_login_msg.id, alice_first_login_tx.transaction.clone()).unwrap(); + + // ======================= Bob + reset_device().unwrap(); + restore_device(bob_device).unwrap(); + set_message_cache(bob_cache).unwrap(); + + helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data); + helper_parse_cipher(alice_first_login_tx.new_network_msg.prd_cipher.unwrap()); + let alice_login_msg = helper_parse_cipher(alice_first_login_tx.new_network_msg.pcd_cipher.unwrap()); + + assert!(alice_login_msg.status == CachedMessageStatus::Login); + + login(alice_login_msg.id, bob_first_login_tx.transaction).unwrap(); +} + +#[wasm_bindgen_test] +fn test_login() { + reset_device().unwrap(); + setup(); + debug!("==============================================\nStarting test_login\n=============================================="); + + // ======================= Alice + restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap(); + + debug!("Alice sends a login transaction to Bob, which creates a new key for him"); + let alice_login_tx = create_login_transaction(1).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let alice_login_tweak_data = helper_get_tweak_data( + &alice_login_tx.transaction, + alice_outputs + ); + + debug!("Parsing Alice login transaction"); + helper_parse_transaction(&alice_login_tx.transaction, &alice_login_tweak_data); + + let alice_device = dump_device().unwrap(); + let alice_cache = dump_message_cache().unwrap(); + + // ============================== Bob + reset_device().unwrap(); + restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap(); + + debug!("Bob finds out the login demand from Alice"); + helper_parse_transaction(&alice_login_tx.transaction, &alice_login_tweak_data); + helper_parse_cipher(alice_login_tx.new_network_msg.prd_cipher.unwrap()); + let alice_login_msg = helper_parse_cipher(alice_login_tx.new_network_msg.pcd_cipher.unwrap()); + + // Bob must confirm that he agrees to log in + + // Boutons "login" ou "Refuser" + // At this point Bob can fire up the revokation output if the login demand is illegitimate + // revoke_paired_device(1).unwrap(); + // OR it must answer with a login transaction to Alice + let bob_login_tx = create_login_transaction(1).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let bob_login_tweak_data = helper_get_tweak_data(&bob_login_tx.transaction, bob_outputs); + + debug!("Bob parses his own login transaction"); + helper_parse_transaction(&bob_login_tx.transaction, &bob_login_tweak_data); + + login(alice_login_msg.id, alice_login_tx.transaction.clone()).unwrap(); + + // =================== Alice + + reset_device().unwrap(); + restore_device(alice_device).unwrap(); + set_message_cache(alice_cache).unwrap(); + + helper_parse_transaction(&bob_login_tx.transaction, &bob_login_tweak_data); + helper_parse_cipher(bob_login_tx.new_network_msg.prd_cipher.unwrap()); + let bob_login_msg = helper_parse_cipher(bob_login_tx.new_network_msg.pcd_cipher.unwrap()); + + assert!(bob_login_msg.status == CachedMessageStatus::Login); + + login(bob_login_msg.id, alice_login_tx.transaction).unwrap(); +} diff --git a/tests/prd.rs b/tests/prd.rs new file mode 100644 index 0000000..5fea339 --- /dev/null +++ b/tests/prd.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; + +use log::debug; +use sdk_client::api::{ + create_confirmation_transaction, create_notification_transaction, dump_device, dump_message_cache, get_outputs, reset_device, restore_device, set_message_cache, setup +}; +use sdk_common::network::{ + CachedMessage, CachedMessageStatus, Pcd +}; +use sdk_common::sp_client::bitcoin::OutPoint; +use sdk_common::sp_client::spclient::OwnedOutput; + +use tsify::JsValueSerdeExt; +use wasm_bindgen_test::*; + +wasm_bindgen_test_configure!(run_in_browser); + +mod utils; + +use utils::*; + +#[wasm_bindgen_test] +fn test_alice_sends_prd_message_to_bob() { + reset_device().unwrap(); + setup(); + debug!("==============================================\nStarting test_alice_sends_prd_message_to_bob\n=============================================="); + + // ============================ Alice + restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap(); + + // Alice first puts her message in a pcd + let pcd = Pcd::new("TEST".to_owned()); + debug!("Alice notified Bob about a message it sent"); + + let notification_tx = + create_notification_transaction(helper_get_bob_address(), pcd, 1).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + let notification_tweak_data = helper_get_tweak_data( + ¬ification_tx.transaction, + alice_outputs + ); + + debug!("Alice parses her own notification transaction"); + // Alice parse her own transaction to update her utxos + helper_parse_transaction( + ¬ification_tx.transaction, + ¬ification_tweak_data, + ); + + reset_device().unwrap(); + restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap(); + + debug!("bob parses the transaction and the message"); + helper_parse_transaction(¬ification_tx.transaction, ¬ification_tweak_data); + helper_parse_cipher(notification_tx.new_network_msg.prd_cipher.unwrap()); + let bob_notification_msg = helper_parse_cipher(notification_tx.new_network_msg.pcd_cipher.unwrap()); + + let msg_dump = dump_message_cache().unwrap(); + debug!("bob_wallet: {:?}", dump_device()); + debug!("bob_notification_msg: {:?}", msg_dump); + debug!("commited_in: {:?}", msg_dump.get(0).unwrap().find("0x71b37cede4655932a5ce97bb8c4a7845adce96d4f85b64bc699bf74942c19f89")); + + assert!(bob_notification_msg.status == CachedMessageStatus::ReceivedMustConfirm); +} diff --git a/tests/utils.rs b/tests/utils.rs new file mode 100644 index 0000000..4116688 --- /dev/null +++ b/tests/utils.rs @@ -0,0 +1,107 @@ +use std::collections::HashMap; + +use log::debug; +use sdk_client::api::{parse_cipher, parse_new_tx, reset_device, restore_device_from_sp_wallet}; +use sdk_common::network::{ + CachedMessage, NewTxMessage, +}; +use sdk_common::sp_client::bitcoin::consensus::deserialize; +use sdk_common::sp_client::bitcoin::hex::FromHex; +use sdk_common::sp_client::bitcoin::secp256k1::PublicKey; +use sdk_common::sp_client::bitcoin::{OutPoint, ScriptBuf, Transaction}; +use sdk_common::sp_client::silentpayments::utils::receiving::{ + calculate_tweak_data, get_pubkey_from_input, +}; +use sdk_common::sp_client::spclient::{OwnedOutput, SpWallet}; +use serde_json; + +// We're using alice and bob for clarity, but it's important to remember that for pairing and login Alice and Bob are the same person +pub const ALICE_START_WALLET: &str = "{\"client\":{\"network\":\"regtest\",\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]}},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +pub const ALICE_LOGIN_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}}}},\"tx_history\":[]}"; +pub const BOB_START_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +pub const BOB_LOGIN_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +pub const ALICE_ANSWER_CACHE: &str = "[{\"id\":1436790358,\"status\":\"MustSpendConfirmation\",\"prd_cipher\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590537,\"error\":null}]"; +pub const ALICE_FINAL_CACHE: &str = "[{\"id\":1436790358,\"status\":\"Trusted\",\"prd_cipher\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590537,\"error\":null}]"; +pub const BOB_ANSWER_CACHE: &str = "[{\"id\":2887008190,\"status\":\"ReceivedMustConfirm\",\"prd_cipher\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590605,\"error\":null}]"; +pub const BOB_PAIRING_CACHE: &str = "[{\"id\":2853916441,\"status\":\"Pairing\",\"prd_cipher\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\",\"tied_by\":null,\"commitment\":\"7f340cd5f070a4bd8d16077214a0488e43bd41d64d8b2b39ab0fc016c1093eba\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"a86c30250a8e6a8dc9581b3ab2dacafda6446f6c65f4debe124f5870b6796ea1\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062445,\"error\":null}, {\"id\":1045548533,\"status\":\"Closed\",\"prd_cipher\":\"bd2acbc73fc402a8cb57121153f2667b944fe31f67ccdd6031e7d9481642f42ebdae00b572b1be6735ff413ceedccf29d2f0700021c6cf61b954891912968a449e6cb735e9344d90db21268ff596f844db358bc4852358ac89a71e81179b249b499a6b70bef341ff71737ea0a9a7e3f2a90bb41d376272410a18ec367d5b6f417420d6d6ee06a132c263269cba281c1fa6e644b5beed716783e973594f5e9da76c28bdc10968ec7e49031924fb8051ec80d27f87e943f884263cb1a273b18f79\",\"plaintext\":[\"PAIRING\"],\"commited_in\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\",\"tied_by\":1,\"commitment\":\"213c1295d6721f3194745063190487e73853c21373218255d2af20c4b1ba6a7b\",\"sender\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"recipient\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"shared_secret\":\"094849bcf340d0791fa0bae31c9b58b8572ad3c9bd028de3a26e501b578cb24b\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062534,\"error\":null}]"; +pub const ALICE_PAIRING_CACHE: &str = "[{\"id\":2059106889,\"status\":\"Closed\",\"prd_cipher\":\"6634050737f9dc18b187c69872943f9a11764252bac9e163fcb7480fd0aa3cf543f7b0b7eef9579d1ddba0b79fdf8c59747050313d0518ea4c8d23d2665948549efd72d0fde7bc8e7a02936de78b7406a31072429d9a81751d5665e9333f8c429c59e47a11b8993583fc5806c8e8695db970247761d11782188c550bd19f7a2c60172104c2892a463f79c19e4173852279012003edf3f777e7c1a95e7d87863d155bcaee1fc4c1b0cb69cab42a45ad5c6271a9c9ba4f79e49a3de2e0fa0aa9bc\",\"plaintext\":[\"PAIRING\"],\"commited_in\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\",\"tied_by\":1,\"commitment\":\"7f340cd5f070a4bd8d16077214a0488e43bd41d64d8b2b39ab0fc016c1093eba\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"a86c30250a8e6a8dc9581b3ab2dacafda6446f6c65f4debe124f5870b6796ea1\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062375,\"error\":null}, {\"id\":3841225687,\"status\":\"Pairing\",\"prd_cipher\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\",\"tied_by\":null,\"commitment\":\"213c1295d6721f3194745063190487e73853c21373218255d2af20c4b1ba6a7b\",\"sender\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"recipient\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"shared_secret\":\"094849bcf340d0791fa0bae31c9b58b8572ad3c9bd028de3a26e501b578cb24b\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062605,\"error\":null}]"; +pub const ALICE_CHALLENGE_CACHE: &str = "[{\"id\":1436790358,\"status\":\"SentWaitingConfirmation\",\"prd_cipher\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1723198590537,\"error\":null}]"; +pub const BOB_CHALLENGE_CACHE: &str = "[{\"id\":3192205787,\"status\":\"ReceivedMustConfirm\",\"commited_in\":\"662e6513e108fc6c0abea3da59c9c710c44c3d7cf81973398c526bbd1d6f69e5:0\",\"tied_by\":null,\"commitment\":\"b5aa9b3bc455c56070269904271b798e50b3076fdbbc7bbfcf4cb44c7cf21bc7\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"4d71a5e617a3bd6923ea1bac26e6d9981edbd1615556264c1271458172337003\",\"prd_cipher\":null,\"prd\":{\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"key\":[84,186,61,88,197,78,128,88,176,85,201,247,228,113,97,153,123,129,14,22,10,134,122,221,61,134,54,12,65,5,162,45],\"pcd_commitment\":\"8eec815cc389b7c5ff573533620051fbb97ba025bd0cf3cb2e903b632652fd2b\",\"error\":null},\"pcd_cipher\":null,\"pcd\":{\"message\":\"TEST\",\"error\":null},\"pcd_commitment\":\"8eec815cc389b7c5ff573533620051fbb97ba025bd0cf3cb2e903b632652fd2b\",\"confirmed_by\":null,\"timestamp\":1723724725299,\"error\":null}]"; +pub const ALICE_PAIRED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\"}}"; +pub const BOB_PAIRED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\"}}"; +pub const ALICE_LOGGED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; +pub const BOB_LOGGED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; +pub const ALICE_CHALLENGE_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; +pub const BOB_CHALLENGE_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"0754a8c68a836ee37e00a4fbc6109bd10558bae0f83eaea31efec3a16dc7ac68:0\":{\"blockheight\":0,\"tweak\":\"77db25e5a74948afe852209cdd84445708bf71d2a2465d4feb81075b4864aa62\",\"amount\":1200,\"script\":\"5120c11362725586664cd5001737afde129c61b82f16c0a661972453e423e937c91c\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; +pub const ALICE_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":\"Unspent\"},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\":{\"blockheight\":0,\"tweak\":\"de507c854cee16d2e157fbf6c6dbfd2e721b861efc7f657bb724790fc7829665\",\"amount\":349,\"script\":\"5120028143243ed5d4554e60d96ee61fdf6f6e359a9083311c210645c0a7fef51248\",\"label\":null,\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; +pub const BOB_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:1\":{\"blockheight\":0,\"tweak\":\"281ea54f74e5f6582a7462bdd9397b9a786f97455e858e7901a6a4fa95f39192\",\"amount\":654,\"script\":\"5120aa4395e2be9cbce580e94f4308d64422da251b7df12fb8c571675d40cc50cf00\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\":{\"blockheight\":0,\"tweak\":\"21fc32bded971dd15387671436232f17d932e18758f69b476219e2d6e688767f\",\"amount\":1200,\"script\":\"5120230d06322d10a5838634df3c55eef9959a1c0c144108e0416b9687eaf22e6baa\",\"label\":null,\"spend_status\":{\"Spent\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; +pub const ALICE_FINAL_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\":{\"blockheight\":0,\"tweak\":\"de507c854cee16d2e157fbf6c6dbfd2e721b861efc7f657bb724790fc7829665\",\"amount\":349,\"script\":\"5120028143243ed5d4554e60d96ee61fdf6f6e359a9083311c210645c0a7fef51248\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; + +pub fn helper_switch_device(wallet: String) { + reset_device().unwrap(); + restore_device_from_sp_wallet(wallet.clone()).unwrap(); +} + +pub fn helper_get_alice_address() -> String { + let wallet: SpWallet = serde_json::from_str(ALICE_START_WALLET).unwrap(); + wallet.get_client().get_receiving_address() +} + +pub fn helper_get_bob_address() -> String { + let wallet: SpWallet = serde_json::from_str(BOB_START_WALLET).unwrap(); + wallet.get_client().get_receiving_address() +} + +pub fn helper_get_tweak_data(transaction: &str, outpoints: HashMap) -> String { + let tx = deserialize::(&Vec::from_hex(transaction).unwrap()).unwrap(); + let mut outpoint_data = vec![]; + let mut witnesses = vec![]; + let mut spks = vec![]; + for prevout in tx.input { + outpoint_data.push(( + prevout.previous_output.txid.to_string(), + prevout.previous_output.vout, + )); + witnesses.push(prevout.witness); + if let Some(output) = outpoints.get(&prevout.previous_output) { + spks.push(ScriptBuf::from_hex(&output.script).unwrap()); + } + } + let mut input_pubkeys = vec![]; + for (spk, witness) in spks.iter().zip(witnesses) { + let input_pubkey = + get_pubkey_from_input(&vec![], &witness.to_vec(), spk.as_bytes()).unwrap(); + input_pubkeys.push(input_pubkey.unwrap()); + } + let ref_pubkeys: Vec<&PublicKey> = input_pubkeys.iter().collect(); + let tweak_data = calculate_tweak_data(&ref_pubkeys, &outpoint_data).unwrap(); + tweak_data.to_string() +} + +pub fn helper_parse_transaction(transaction: &str, tweak_data: &str) -> CachedMessage { + let new_tx_msg = serde_json::to_string(&NewTxMessage::new( + transaction.to_owned(), + Some(tweak_data.to_owned()), + )) + .unwrap(); + debug!("new_tx_msg: {:?}", new_tx_msg); + let result = parse_new_tx(new_tx_msg, 0, 1); + match result { + Ok(m) => { + if m.is_some() { + m.unwrap() + } else { + panic!("Failed to find our tx"); + } + }, + Err(e) => panic!("Unexpected error: {}", e.message), + } +} + +pub fn helper_parse_cipher(cipher_msg: String) -> CachedMessage { + let result = parse_cipher(cipher_msg, 1); + match result { + Ok(r) => return r, + Err(e) => panic!("Unexpected error: {}", e.message), + }; +} From 45628edb61d0152b6a108cdaee22cc4b985efd76 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Tue, 20 Aug 2024 12:22:03 +0200 Subject: [PATCH 03/14] Add Process --- src/api.rs | 126 ++++++++++++++++++------------------------ src/lib.rs | 1 - src/user.rs | 140 +---------------------------------------------- tests/pairing.rs | 10 +++- tests/prd.rs | 18 +++++- tests/utils.rs | 2 + 6 files changed, 79 insertions(+), 218 deletions(-) diff --git a/src/api.rs b/src/api.rs index 6f5ec06..0ecfd7a 100644 --- a/src/api.rs +++ b/src/api.rs @@ -14,6 +14,8 @@ use anyhow::Error as AnyhowError; use sdk_common::crypto::{ AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, AnkSharedSecret, KeyInit, Purpose, }; +use sdk_common::device::{REVOKATION_INDEX, SESSION_INDEX}; +use sdk_common::process::{Member, PairingPcd, Process, Role, ValidationRules}; use sdk_common::sp_client::bitcoin::blockdata::fee_rate; use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; use sdk_common::sp_client::bitcoin::hashes::HashEngine; @@ -47,20 +49,18 @@ use wasm_bindgen::convert::FromWasmAbi; use wasm_bindgen::prelude::*; use sdk_common::network::{ - self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage, Pcd, Prd + self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage, Pcd, Prd, PrdType }; use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address}; - -use crate::wallet::{generate_sp_wallet, lock_freezed_utxos}; use sdk_common::sp_client::spclient::{ derive_keys_from_seed, OutputList, OutputSpendStatus, OwnedOutput, Recipient, SpClient, }; use sdk_common::sp_client::spclient::{SpWallet, SpendKey}; +use sdk_common::device::Device; -use crate::user::{lock_local_device, set_new_device, Device, LOCAL_DEVICE}; +use crate::user::{lock_local_device, set_new_device, LOCAL_DEVICE}; use crate::{lock_messages, CACHEDMESSAGES}; - -use crate::process::Process; +use crate::wallet::{generate_sp_wallet, lock_freezed_utxos}; pub type ApiResult = Result; @@ -218,7 +218,7 @@ pub fn create_new_device(birthday: u32, network_str: String) -> ApiResult ApiResult<()> { +pub fn pair_device(nym: String, message_id: u32, incoming_pairing_txid: String) -> ApiResult { let mut local_device = lock_local_device()?; // check that we're still in pairing phase @@ -270,75 +270,25 @@ pub fn pair_device(message_id: u32, incoming_pairing_txid: String) -> ApiResult< )?; message.status = CachedMessageStatus::Closed; + + let pairing_pcd = PairingPcd::new( + nym, + local_device.get_wallet().get_client().get_receiving_address().try_into().unwrap(), + local_device.get_paired_device_info().unwrap().address.try_into().unwrap(), + SESSION_INDEX, + REVOKATION_INDEX, + Txid::from_str(&incoming_pairing_txid)?, + pairing_tx.txid + ); + + let pairing_process = Process::new_pairing_process(pairing_pcd, pairing_tx.txid); + + Ok(pairing_process) } else { return Err(ApiError { message: format!("Can't find message with id {}", message_id), }); } - - Ok(()) -} - -#[derive(Tsify, Serialize, Deserialize)] -#[tsify(into_wasm_abi)] -#[allow(non_camel_case_types)] -pub struct get_process_return(Vec); - -#[wasm_bindgen] -pub fn get_processes() -> ApiResult { - let MEMBERS: [String;5] = [ - "tsp1qqdvmxycf3c3tf2qhpev0npx25rj05270d6j2pcsrfk2qn5gdy0rpwq6hd9u9sztl3fwmrzzqafzl3ymkq86aqfz5jl5egdkz72tqmhcnrswdz3pk".to_owned(), - "tsp1qqwafwn7dcr9d6ta0w8fjtd9s53u72x9qmmtgd8adqr7454xl90a5jq3vw23l2x8ypt55nrg7trl9lwz5xr5j357ucu4sf9rfmvc0zujcpqcps6rm".to_owned(), - "tsp1qqw02t5hmg5rxpjdkmjdnnmhvuc76wt6vlqdmn2zafnh6axxjd6e2gqcz04gzvnkzf572mur8spyx2a2s8sqzll2ymdpyz59cpl96j4zuvcdvrzxz".to_owned(), - "tsp1qqgpay2r5jswm7vcv24xd94shdf90w30vxtql9svw7qnlnrzd6xt02q7s7z57uw0sssh6c0xddcrryq4mxup93jsh3gfau3autrawl8umkgsyupkm".to_owned(), - "tsp1qqtsqmtgnxp0lsmnxyxcq52zpgxwugwlq8urlprs5pr5lwyqc789gjqhx5qra6g4rszsq43pms6nguee2l9trx905rk5sgntek05hnf7say4ru69y".to_owned(), - ]; - //instances of process - let process1 = Process { - id: 6, - name: String::from("Messaging"), - version: String::from("1.0"), - members: MEMBERS.to_vec(), - html: crate::process::HTML_MESSAGING.to_owned(), - style: crate::process::CSS.to_owned(), - script: "".to_owned(), - }; - let process2 = Process { - id: 7, - name: String::from("Kotpart"), - version: String::from("1.0"), - members: MEMBERS.to_vec(), - html: crate::process::HTML_MESSAGING.to_owned(), - style: crate::process::CSS.to_owned(), - script: "".to_owned(), - }; - let process3 = Process { - id: 8, - name: String::from("Storage"), - version: String::from("1.0"), - members: MEMBERS.to_vec(), - html: crate::process::HTML_MESSAGING.to_owned(), - style: crate::process::CSS.to_owned(), - script: "".to_owned(), - }; - - // vec with the instances of processes - let mut data_process: Vec = Vec::new(); - data_process.push(process1); - data_process.push(process2); - data_process.push(process3); - Ok(get_process_return(data_process)) -} - -#[derive(Debug, Tsify, Serialize, Deserialize)] -#[tsify(from_wasm_abi)] -#[allow(non_camel_case_types)] -pub struct recover_data(Vec); - -impl recover_data { - fn as_inner(&self) -> &[u8] { - &self.0 - } } #[derive(Debug, Tsify, Serialize, Deserialize)] @@ -728,6 +678,7 @@ pub fn parse_cipher(cipher_msg: String, fee_rate: u32) -> ApiResult ApiResult ApiResult ApiResult { @@ -1093,10 +1069,12 @@ pub fn create_notification_transaction( let key: [u8; 32] = Aes256Gcm::generate_key(thread_rng()).into(); let prd = Prd::new( + PrdType::Message, + process, sp_wallet.get_client().get_receiving_address().try_into().unwrap(), key, pcd_commitment - ); + )?; let prd_commitment = sha256sum(prd.to_string().as_bytes()); diff --git a/src/lib.rs b/src/lib.rs index 983e281..4661ad5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ use tsify::Tsify; pub mod api; mod peers; -mod process; mod user; mod wallet; diff --git a/src/user.rs b/src/user.rs index f244aa2..2f8b11d 100644 --- a/src/user.rs +++ b/src/user.rs @@ -25,6 +25,7 @@ use sdk_common::sp_client::bitcoin::secp256k1::constants::SECRET_KEY_SIZE; use sdk_common::sp_client::silentpayments::bitcoin_hashes::sha256; use sdk_common::sp_client::silentpayments::utils::{Network as SpNetwork, SilentPaymentAddress}; use sdk_common::sp_client::spclient::{OutputList, SpWallet, SpendKey}; +use sdk_common::device::Device; use crate::peers::Peer; use crate::wallet::generate_sp_wallet; @@ -58,142 +59,3 @@ pub fn lock_local_device() -> Result> { .get_or_init(|| Mutex::new(Device::default())) .lock_anyhow() } - -#[derive(Debug, Serialize, Deserialize, Clone, Default, Tsify)] -#[tsify(into_wasm_abi, from_wasm_abi)] -pub struct PairedDevice { - pub address: String, - pub outgoing_pairing_transaction: [u8; 32], - pub revokation_index: u32, - pub incoming_pairing_transaction: [u8; 32], - pub current_remote_key: [u8; 32], - pub current_session_outpoint: OutPoint, // This will be spend by remote device to notify us of next login - pub current_session_revokation_outpoint: OutPoint, // remote device can revoke current session by spending this -} - -impl PairedDevice { - pub fn new(address: SilentPaymentAddress, pairing_txid: Txid, revokation_index: u32) -> Self { - let mut pairing_transaction_buf = [0u8; 32]; - pairing_transaction_buf.copy_from_slice(&serialize(&pairing_txid)); - - Self { - address: address.into(), - outgoing_pairing_transaction: pairing_transaction_buf, - revokation_index, - incoming_pairing_transaction: [0u8; 32], - current_session_revokation_outpoint: OutPoint::default(), - current_session_outpoint: OutPoint::default(), - current_remote_key: [0u8; 32], - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, Default, Tsify)] -#[tsify(into_wasm_abi, from_wasm_abi)] -pub struct Device { - sp_wallet: SpWallet, - current_session_outpoint: OutPoint, // This is the notification output of incoming login tx - current_session_key: [u8; 32], - current_session_revokation_outpoint: OutPoint, // This is the revokation outpoint of outgoing login tx - paired_device: Option, -} - -impl Device { - pub fn new(sp_wallet: SpWallet) -> Self { - Self { - sp_wallet, - current_session_outpoint: OutPoint::default(), - current_session_key: [0u8; 32], - current_session_revokation_outpoint: OutPoint::default(), - paired_device: None, - } - } - - pub fn get_wallet(&self) -> &SpWallet { - &self.sp_wallet - } - - pub fn get_mut_wallet(&mut self) -> &mut SpWallet { - &mut self.sp_wallet - } - - pub fn is_linked(&self) -> bool { - self.paired_device.is_some() - } - - pub fn is_pairing(&self) -> bool { - self.current_session_key == [0u8; 32] - } - - pub fn get_paired_device_info(&self) -> Option { - self.paired_device.clone() - } - - pub fn get_next_output_to_spend(&self) -> OutPoint { - self.current_session_outpoint - } - - pub fn get_session_revokation_outpoint(&self) -> OutPoint { - self.current_session_revokation_outpoint - } - - pub fn sign_with_current_session_key(&self) -> Result<()> { - unimplemented!(); - } - - pub fn encrypt_with_current_session_key(&self) -> Result<()> { - unimplemented!(); - } - - pub fn new_link( - &mut self, - link_with: SilentPaymentAddress, - outgoing_pairing_tx: Txid, - revokation_output: u32, - incoming_pairing_tx: Txid, - ) -> Result<()> { - let address_looked_for: String = link_with.into(); - if let Some(paired_device) = self.paired_device.as_ref() { - return Err(Error::msg(format!( - "Found an already paired device with address {} and revokable by {}:{}", - paired_device.address, - Txid::from_byte_array(paired_device.outgoing_pairing_transaction), - paired_device.revokation_index - ))); - } else { - let mut new_device = - PairedDevice::new(link_with, outgoing_pairing_tx, revokation_output); - new_device.incoming_pairing_transaction = incoming_pairing_tx.to_byte_array(); - self.paired_device = Some(new_device); - } - - Ok(()) - } - - // We call that when we spent to the remote device and it similarly spent to us - pub fn update_session( - &mut self, - new_session_key: SecretKey, - new_session_outpoint: OutPoint, - new_revokation_outpoint: OutPoint, - new_remote_key: XOnlyPublicKey, - new_remote_session_outpoint: OutPoint, - new_remote_revokation_outpoint: OutPoint, - ) -> Result<()> { - if !self.is_linked() { - return Err(Error::msg("Can't update an unpaired device")); - } - self.paired_device - .as_mut() - .map(|d| { - d.current_remote_key = new_remote_key.serialize(); - d.current_session_outpoint = new_remote_session_outpoint; - d.current_session_revokation_outpoint = new_remote_revokation_outpoint; - }); - self.current_session_key = new_session_key.secret_bytes(); - self.current_session_outpoint = new_session_outpoint; - self.current_session_revokation_outpoint = new_revokation_outpoint; - - Ok(()) - } -} diff --git a/tests/pairing.rs b/tests/pairing.rs index 2543070..d3686d0 100644 --- a/tests/pairing.rs +++ b/tests/pairing.rs @@ -79,7 +79,13 @@ fn test_pairing() { helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); debug!("Bob pairs device with Alice"); - pair_device(bob_pairing_tx.new_network_msg.id, incoming_txid.to_string()).unwrap(); + let pairing_process = pair_device(DEFAULT_NYM.to_owned(), bob_pairing_tx.new_network_msg.id, incoming_txid.to_string()).unwrap(); + + // sign the pairing process + + // send it to Alice so that she can sign it too + + // commit it to a transaction to make it public // ======================== Alice reset_device().unwrap(); @@ -95,7 +101,7 @@ fn test_pairing() { assert!(bob_pairing_msg.status == CachedMessageStatus::Pairing); debug!("Alice pairs device"); - pair_device(alice_msg_id, bob_pairing_tx.txid).unwrap(); + pair_device(DEFAULT_NYM.to_owned(), alice_msg_id, bob_pairing_tx.txid).unwrap(); } #[wasm_bindgen_test] diff --git a/tests/prd.rs b/tests/prd.rs index 5fea339..736d487 100644 --- a/tests/prd.rs +++ b/tests/prd.rs @@ -7,9 +7,12 @@ use sdk_client::api::{ use sdk_common::network::{ CachedMessage, CachedMessageStatus, Pcd }; -use sdk_common::sp_client::bitcoin::OutPoint; +use sdk_common::process::{Process, Role, ValidationRules}; +use sdk_common::sp_client::bitcoin::hashes::Hash; +use sdk_common::sp_client::bitcoin::{OutPoint, Txid}; use sdk_common::sp_client::spclient::OwnedOutput; +use serde_json::Value; use tsify::JsValueSerdeExt; use wasm_bindgen_test::*; @@ -32,8 +35,19 @@ fn test_alice_sends_prd_message_to_bob() { let pcd = Pcd::new("TEST".to_owned()); debug!("Alice notified Bob about a message it sent"); + let empty_process = Process::new( + "empty".to_owned(), + vec![], + ValidationRules::new(0.0, Role::User), + Txid::all_zeros(), + String::default(), + String::default(), + String::default(), + Value::Null + ); + let notification_tx = - create_notification_transaction(helper_get_bob_address(), pcd, 1).unwrap(); + create_notification_transaction(helper_get_bob_address(), empty_process, pcd, 1).unwrap(); let get_outputs_result = get_outputs().unwrap(); diff --git a/tests/utils.rs b/tests/utils.rs index 4116688..ed8e4d1 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -37,6 +37,8 @@ pub const ALICE_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"d pub const BOB_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:1\":{\"blockheight\":0,\"tweak\":\"281ea54f74e5f6582a7462bdd9397b9a786f97455e858e7901a6a4fa95f39192\",\"amount\":654,\"script\":\"5120aa4395e2be9cbce580e94f4308d64422da251b7df12fb8c571675d40cc50cf00\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\":{\"blockheight\":0,\"tweak\":\"21fc32bded971dd15387671436232f17d932e18758f69b476219e2d6e688767f\",\"amount\":1200,\"script\":\"5120230d06322d10a5838634df3c55eef9959a1c0c144108e0416b9687eaf22e6baa\",\"label\":null,\"spend_status\":{\"Spent\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; pub const ALICE_FINAL_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\":{\"blockheight\":0,\"tweak\":\"de507c854cee16d2e157fbf6c6dbfd2e721b861efc7f657bb724790fc7829665\",\"amount\":349,\"script\":\"5120028143243ed5d4554e60d96ee61fdf6f6e359a9083311c210645c0a7fef51248\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; +pub const DEFAULT_NYM: &str = "AliceBob"; + pub fn helper_switch_device(wallet: String) { reset_device().unwrap(); restore_device_from_sp_wallet(wallet.clone()).unwrap(); From 287f74136e7ec10252d2f291617f7b7a3cf93d90 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Wed, 28 Aug 2024 09:51:40 +0200 Subject: [PATCH 04/14] Implement minimal prd/pcd, remove challenges --- Cargo.toml | 6 +- src/api.rs | 918 ++++++++++++--------------------------------- src/lib.rs | 45 +++ src/process.rs | 405 -------------------- src/user.rs | 1 + src/wallet.rs | 2 +- tests/challenge.rs | 153 -------- tests/pairing.rs | 303 +++++---------- tests/prd.rs | 81 ---- tests/utils.rs | 17 +- 10 files changed, 391 insertions(+), 1540 deletions(-) delete mode 100644 src/process.rs delete mode 100644 tests/challenge.rs delete mode 100644 tests/prd.rs diff --git a/Cargo.toml b/Cargo.toml index 4324f32..23ae408 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,11 +15,9 @@ wasm-bindgen = "0.2.91" getrandom = { version="0.2.12", features = ["js"] } wasm-logger = "0.2.0" rand = "0.8.5" -log = "0.4.6" tsify = { git = "https://github.com/Sosthene00/tsify", branch = "next" } -# sdk_common = { path = "../sdk_common" } -sdk_common = { git = "https://git.4nkweb.com/4nk/sdk_common.git", branch = "dev" } -shamir = { git = "https://github.com/Sosthene00/shamir", branch = "master" } +sdk_common = { path = "../sdk_common" } +# sdk_common = { git = "https://git.4nkweb.com/4nk/sdk_common.git", branch = "dev" } [dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/src/api.rs b/src/api.rs index 0ecfd7a..6ee8900 100644 --- a/src/api.rs +++ b/src/api.rs @@ -2,20 +2,21 @@ use std::any::Any; use std::borrow::Borrow; use std::collections::HashMap; use std::io::Write; +use std::ops::Index; use std::str::FromStr; use std::string::FromUtf8Error; use std::sync::{Mutex, OnceLock, PoisonError}; use std::time::{Duration, Instant}; -use log::{debug, warn}; +use sdk_common::log::{debug, warn}; use rand::{thread_rng, Fill, Rng, RngCore}; use anyhow::Error as AnyhowError; use sdk_common::crypto::{ AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, AnkSharedSecret, KeyInit, Purpose, }; -use sdk_common::device::{REVOKATION_INDEX, SESSION_INDEX}; -use sdk_common::process::{Member, PairingPcd, Process, Role, ValidationRules}; +use sdk_common::process::{Process, ValidationRules}; +use sdk_common::signature; use sdk_common::sp_client::bitcoin::blockdata::fee_rate; use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; use sdk_common::sp_client::bitcoin::hashes::HashEngine; @@ -41,16 +42,18 @@ use sdk_common::sp_client::silentpayments::{ utils::{Network as SpNetwork, SilentPaymentAddress}, Error as SpError, }; -use serde_json::{Error as SerdeJsonError, Value}; +use sdk_common::uuid::Uuid; +use serde_json::{Error as SerdeJsonError, Map, Value}; use serde::{Deserialize, Serialize}; use tsify::{JsValueSerdeExt, Tsify}; -use wasm_bindgen::convert::FromWasmAbi; +use wasm_bindgen::convert::{FromWasmAbi, VectorFromWasmAbi}; use wasm_bindgen::prelude::*; use sdk_common::network::{ - self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage, Pcd, Prd, PrdType -}; + self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage}; +use sdk_common::pcd::{AnkPcdHash, Pcd, Member}; +use sdk_common::prd::{AnkPrdHash, Prd, PrdType}; use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address}; use sdk_common::sp_client::spclient::{ derive_keys_from_seed, OutputList, OutputSpendStatus, OwnedOutput, Recipient, SpClient, @@ -59,12 +62,13 @@ use sdk_common::sp_client::spclient::{SpWallet, SpendKey}; use sdk_common::device::Device; use crate::user::{lock_local_device, set_new_device, LOCAL_DEVICE}; -use crate::{lock_messages, CACHEDMESSAGES}; +use crate::{lock_messages, lock_processes, ProcessState, ProcessStatus, RelevantProcess, CACHEDMESSAGES, CACHEDPROCESSES}; use crate::wallet::{generate_sp_wallet, lock_freezed_utxos}; pub type ApiResult = Result; const IS_TESTNET: bool = true; +const DEFAULT_AMOUNT: Amount = Amount::from_sat(1000); #[derive(Debug, PartialEq, Eq)] pub struct ApiError { @@ -188,15 +192,6 @@ pub fn get_address() -> ApiResult { .get_receiving_address()) } -#[wasm_bindgen] -pub fn restore_device_from_sp_wallet(sp_wallet: String) -> ApiResult { - let sp_wallet: SpWallet = serde_json::from_str(&sp_wallet)?; - - let our_address = set_new_device(sp_wallet)?; - - Ok(our_address) -} - #[wasm_bindgen] pub fn restore_device(device_str: String) -> ApiResult<()> { let device: Device = serde_json::from_str(&device_str)?; @@ -208,6 +203,15 @@ pub fn restore_device(device_str: String) -> ApiResult<()> { Ok(()) } +#[wasm_bindgen] +pub fn create_device_from_sp_wallet(sp_wallet: String) -> ApiResult { + let sp_wallet: SpWallet = serde_json::from_str(&sp_wallet)?; + + let our_address = set_new_device(sp_wallet)?; + + Ok(our_address) +} + #[wasm_bindgen] pub fn create_new_device(birthday: u32, network_str: String) -> ApiResult { let sp_wallet = generate_sp_wallet(None, Network::from_core_arg(&network_str)?)?; @@ -218,77 +222,20 @@ pub fn create_new_device(birthday: u32, network_str: String) -> ApiResult ApiResult { +pub fn pair_device(uuid: String, new_device_address: String, state: String) -> ApiResult<()> { let mut local_device = lock_local_device()?; - // check that we're still in pairing phase - if !local_device.is_pairing() { + if local_device.is_linked() { return Err(ApiError { message: "Already paired".to_owned(), }); } - let mut messages = lock_messages()?; + local_device.set_process_uuid(Uuid::parse_str(&uuid).map_err(|e| ApiError { message: e.to_string() })?); + local_device.push_paired_device(new_device_address.try_into().map_err(|_| ApiError { message: "Invalid address".to_owned() })?); + local_device.update_latest_state(serde_json::from_str(&state)?); - let my_address = local_device - .get_wallet() - .get_client() - .get_receiving_address(); - - if let Some(message) = messages.iter_mut().find(|m| m.id == message_id) { - if message.status != CachedMessageStatus::Pairing { - return Err(ApiError { - message: "Message is not pairing message".to_owned(), - }); - } - let link_with = if Some(my_address.as_str()) == message.sender.as_ref().map(|s| s.as_str()) - { - message.recipient.as_ref().ok_or(ApiError { - message: "Missing recipient".to_owned(), - })? - } else if Some(my_address.as_str()) == message.recipient.as_ref().map(|s| s.as_str()) { - message.sender.as_ref().ok_or(ApiError { - message: "Missing sender".to_owned(), - })? - } else { - // This should never happen - return Err(ApiError { - message: "We're not part of that message".to_owned(), - }); - }; - let revokation_index = message.tied_by.ok_or(ApiError { - message: "Missing tied_by".to_owned(), - })?; - let pairing_tx = message.commited_in.ok_or(ApiError { - message: "Missing commited_in".to_owned(), - })?; - local_device.new_link( - SilentPaymentAddress::try_from(link_with.as_str()).unwrap(), - pairing_tx.txid, - revokation_index, - Txid::from_str(&incoming_pairing_txid)?, - )?; - - message.status = CachedMessageStatus::Closed; - - let pairing_pcd = PairingPcd::new( - nym, - local_device.get_wallet().get_client().get_receiving_address().try_into().unwrap(), - local_device.get_paired_device_info().unwrap().address.try_into().unwrap(), - SESSION_INDEX, - REVOKATION_INDEX, - Txid::from_str(&incoming_pairing_txid)?, - pairing_tx.txid - ); - - let pairing_process = Process::new_pairing_process(pairing_pcd, pairing_tx.txid); - - Ok(pairing_process) - } else { - return Err(ApiError { - message: format!("Can't find message with id {}", message_id), - }); - } + Ok(()) } #[derive(Debug, Tsify, Serialize, Deserialize)] @@ -302,57 +249,6 @@ impl outputs_list { } } -#[wasm_bindgen] -pub fn login(message_id: u32, outgoing_pairing_transaction: String) -> ApiResult<()> { - let mut local_device = lock_local_device()?; - let pairing_transaction: Transaction = - deserialize(&Vec::from_hex(&outgoing_pairing_transaction)?)?; - let pairing_transaction_txid = pairing_transaction.txid(); - - let messages = lock_messages()?; - - let login_output = pairing_transaction - .output - .first() - .expect("Transaction has at least one output"); - let new_remote_key = XOnlyPublicKey::from_slice(&login_output.script_pubkey.as_bytes()[2..])?; - - let new_session_key: SecretKey; - let notification_outpoint: OutPoint; - if let Some(message) = messages.iter().find(|m| m.id == message_id) { - notification_outpoint = message - .commited_in - .expect("message without commitment outpoint"); - let sp_wallet = local_device.get_wallet(); - let spendable_outputs = sp_wallet.get_outputs().to_spendable_list(); - - let output = spendable_outputs - .get(¬ification_outpoint) - .ok_or(ApiError { - message: "Unknown outpoint".to_owned(), - })?; - - let spend_key = sp_wallet.get_client().try_get_secret_spend_key()?; - let tweak = SecretKey::from_slice(&Vec::from_hex(&output.tweak)?)?; - new_session_key = spend_key.add_tweak(&tweak.into())?; - } else { - return Err(ApiError { - message: "Unknown message".to_owned(), - }); - } - - local_device.update_session( - new_session_key, - notification_outpoint, - OutPoint::new(pairing_transaction_txid, 1), - new_remote_key, - OutPoint::new(pairing_transaction_txid, 0), - OutPoint::new(notification_outpoint.txid, 1), - ); - - Ok(()) -} - #[wasm_bindgen] pub fn logout() -> ApiResult<()> { unimplemented!(); @@ -427,14 +323,15 @@ pub fn reset_device() -> ApiResult<()> { fn handle_transaction( updated: HashMap, tx: &Transaction, - sp_wallet: &mut SpWallet, tweak_data: PublicKey, ) -> anyhow::Result { + let device = lock_local_device()?; + let sp_wallet = device.get_wallet(); + let op_return = tx.output.iter().find(|o| o.script_pubkey.is_op_return()); - let commitment = if op_return.is_none() { - vec![] - } else { - op_return.unwrap().script_pubkey.as_bytes()[2..].to_vec() + let mut commitment = [0u8; 32]; + if op_return.is_some() { + commitment.copy_from_slice(&op_return.unwrap().script_pubkey.as_bytes()[2..]); }; let commitment_str = commitment.to_lower_hex_string(); @@ -453,58 +350,12 @@ fn handle_transaction( // empty utxo_destroyed means we received this transaction if utxo_destroyed.is_empty() { - // We first check for faucet transactions - if let Some(message) = messages.iter_mut().find(|m| { - if m.status == CachedMessageStatus::FaucetWaiting { - m.commitment.as_ref() == Some(&commitment_str) - } else { - false - } - }) { - message.status = CachedMessageStatus::Closed; - message.commited_in = utxo_created - .into_iter() - .next() - .map(|(outpoint, _)| *outpoint); - return Ok(message.clone()); - } - - // we inspect inputs looking for links with previous tx - for input in tx.input.iter() { - if let Some(message) = messages - .iter_mut() - .find(|m| m.confirmed_by == Some(input.previous_output)) - { - // If we are receiver, that's pretty much it - message.status = CachedMessageStatus::Trusted; - return Ok(message.clone()); - } else if let Some(message) = messages.iter_mut().find(|m| { - m.commited_in == Some(input.previous_output) - && m.status == CachedMessageStatus::SentWaitingConfirmation - }) { - // sender needs to spent it back again to receiver - let (outpoint, output) = utxo_created.into_iter().next().unwrap(); - - message.confirmed_by = Some(outpoint.clone()); - message.status = CachedMessageStatus::MustSpendConfirmation; - - // Caller must interpret this message as "do spend confirmed_by outpoint to receiver" - return Ok(message.clone()); - } - } - - // if we've found nothing we are being notified let shared_point = sp_utils::receiving::calculate_ecdh_shared_secret( &tweak_data, &sp_wallet.get_client().get_scan_key(), ); let shared_secret = AnkSharedSecret::new(shared_point); - // debug!( - // "Shared secret: {}", - // shared_secret.to_byte_array().to_lower_hex_string() - // ); - let mut plaintext: Vec = vec![]; if let Some(message) = messages.iter_mut().find(|m| { if m.status != CachedMessageStatus::CipherWaitingTx { @@ -520,17 +371,13 @@ fn handle_transaction( }) { let (outpoint, output) = utxo_created.into_iter().next().unwrap(); - let cipher_msg: Prd = serde_json::from_slice(&plaintext)?; - message.commited_in = Some(outpoint.clone()); - // freeze the commitment utxo - let mut freezed_utxos = lock_freezed_utxos()?; - freezed_utxos.insert(*outpoint); + let prd = Prd::extract_from_message(&plaintext, commitment)?; - message.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); + message.prd = Some(prd.to_string()); + message.shared_secrets.push(shared_secret.to_byte_array().to_lower_hex_string()); message.commitment = Some(commitment_str); - message.sender = Some(cipher_msg.sender); - message.recipient = Some(sp_wallet.get_client().get_receiving_address()); - message.status = CachedMessageStatus::ReceivedMustConfirm; + message.sender = Some(serde_json::from_str(&prd.sender)?); + message.status = CachedMessageStatus::Opened; return Ok(message.clone()); } else { @@ -540,71 +387,15 @@ fn handle_transaction( .into_iter() .next() .expect("utxo_created shouldn't be empty"); - new_msg.commited_in = Some(outpoint.clone()); - // freeze the commitment utxo - let mut freezed_utxos = lock_freezed_utxos()?; - freezed_utxos.insert(*outpoint); - new_msg.commitment = Some(commitment.to_lower_hex_string()); - new_msg.recipient = Some(sp_wallet.get_client().get_receiving_address()); - new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); + new_msg.shared_secrets.push(shared_secret.to_byte_array().to_lower_hex_string()); new_msg.status = CachedMessageStatus::TxWaitingPrd; messages.push(new_msg.clone()); return Ok(new_msg.clone()); } } else { - // We are sender of a transaction - // We only need to return the message - // eiter this is notification, a challenge, or response to a challenge - // if notification, commitment is the same than in the message - if let Some(message) = messages.iter().find(|m| { - if commitment.is_empty() || m.commitment.is_none() { - return false; - } - match m.status { - CachedMessageStatus::SentWaitingConfirmation - | CachedMessageStatus::Pairing - | CachedMessageStatus::Login => { - // commitment we're looking for is simply what's in the message - m.commitment - .as_ref() - .map(|c| Vec::from_hex(&c).unwrap()) - .unwrap() - == commitment - } - CachedMessageStatus::ReceivedMustConfirm => { - // we look for a message that has commited_in as input of the transaction - if let Some(_) = tx - .input - .iter() - .find(|i| Some(i.previous_output) == m.commited_in) - { - return true; - } else { - return false; - } - } - CachedMessageStatus::MustSpendConfirmation | CachedMessageStatus::Trusted => { - // we look for a message that has confirm_by as input - if let Some(_) = tx - .input - .iter() - .find(|i| Some(i.previous_output) == m.confirmed_by) - { - return true; - } else { - return false; - } - } - _ => return false, - } - }) { - return Ok(message.clone()); - } else { - return Err(anyhow::Error::msg( - "Failed to find the message for one of our transactions", - )); - } + // We're sender of the transaction, do nothing + return Ok(CachedMessage::new()); } } @@ -619,12 +410,15 @@ fn process_transaction( let tweak_data = PublicKey::from_str(&tweak_data_hex)?; - let mut device = lock_local_device()?; - let wallet = device.get_mut_wallet(); - let updated = wallet.update_wallet_with_transaction(&tx, blockheight, tweak_data)?; + let updated: HashMap; + { + let mut device = lock_local_device()?; + let wallet = device.get_mut_wallet(); + updated = wallet.update_wallet_with_transaction(&tx, blockheight, tweak_data)?; + } if updated.len() > 0 { - let updated_msg = handle_transaction(updated, &tx, wallet, tweak_data)?; + let updated_msg = handle_transaction(updated, &tx, tweak_data)?; return Ok(Some(updated_msg)); } @@ -658,64 +452,74 @@ pub fn parse_cipher(cipher_msg: String, fee_rate: u32) -> ApiResult { - m.try_decrypt_prd(cipher.clone()).is_ok() - } - CachedMessageStatus::GotPrdWaitingPcd => { - m.try_decrypt_pcd(cipher.clone()).is_ok() + CachedMessageStatus::TxWaitingPrd | CachedMessageStatus::Opened => { + if let Ok(m) = m.try_decrypt_message(cipher.clone()) { + plain = m; + return true; + } else { return false } } _ => return false, }) { if message.status == CachedMessageStatus::TxWaitingPrd { - let plain = message.try_decrypt_prd(cipher).unwrap(); - debug!("Found message {}", String::from_utf8(plain.clone())?); - let prd: Prd = serde_json::from_slice(&plain)?; - // does the retrieved message match with the commited hash? - let hash = create_commitment(serde_json::to_string(&prd)?); - if Some(hash) != message.commitment { + // debug!("Found message {}", String::from_utf8(plain.clone())?); + let mut commitment = [0u8; 32]; + commitment.copy_from_slice(&Vec::from_hex(message.commitment.as_ref().unwrap())?); + let prd = Prd::extract_from_message(&plain, commitment)?; + + message.prd = Some(prd.to_string()); + message.sender = Some(serde_json::from_str(&prd.sender)?); + message.status = CachedMessageStatus::Opened; + } else { + // debug!("Found message {}", String::from_utf8(plain.clone())?); + // we're receiving a pcd for a prd we already have + let mut pcd = Value::from_str(&String::from_utf8(plain)?)?; + // check that the hash of the pcd is the same than commited in the prd + let pcd_commitment = AnkPcdHash::from_value(&pcd); + let prd: Prd = serde_json::from_str(message.prd.as_ref().unwrap()).unwrap(); + if pcd_commitment.to_string() != prd.pcd_commitment { return Err(ApiError { - message: "Prd doesn't match commitment".to_owned(), + message: format!("Pcd doesn't match commitment: expected {:?}\ngot {}", prd.pcd_commitment, pcd_commitment), }); } - message.prd_type = prd.prd_type.clone(); - message.sender = Some(prd.sender.clone()); - message.pcd_commitment = Some(prd.pcd_commitment.to_string()); - message.prd_cipher = None; - message.prd = Some(prd); - message.status = CachedMessageStatus::GotPrdWaitingPcd; - } else { - let plain = message.try_decrypt_pcd(cipher).unwrap(); - debug!("Found message {}", String::from_utf8(plain.clone())?); - // we're receiving a pcd for a prd we already have - let pcd: Pcd = serde_json::from_slice(&plain)?; - // check that the hash of the pcd is the same than commited in the prd - let pcd_commitment = create_commitment(pcd.to_string()); - if Some(&pcd_commitment) != message.pcd_commitment.as_ref() { - return Err(ApiError { - message: format!("Pcd doesn't match commitment: expected {:?}\ngot {}", message.pcd_commitment.as_ref(), pcd_commitment), - }); + message.pcd = Some(pcd.clone()); + + // Now we decrypt all we can from the pcd + pcd.decrypt_fields(&prd.keys)?; + + // we take a few mandatory informations + let process = pcd["process"].take(); + let uuid = Uuid::parse_str(&prd.process_uuid).expect("prd can't have an invalid uuid"); + // todo check that the uuid in the process we took from pcd is consistent + + // we complete the process we keep in storage + let mut processes = lock_processes()?; + + match prd.prd_type { + PrdType::Init => { + let relevant_process = RelevantProcess { + process: serde_json::from_value(process)?, + states: vec![ProcessState { + commited_in: OutPoint::null(), // At this point process is not commited yet + encrypted_pcd: message.pcd.clone().unwrap(), + keys: prd.keys.clone(), + validation_token: vec![], + }], + current_status: ProcessStatus::Active(message.shared_secrets.clone()) + }; + processes.insert(uuid, relevant_process); + }, + _ => unimplemented!() } - if pcd.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 pcd.message.starts_with("LOGIN") { - message.status = CachedMessageStatus::Login; - } else { - message.status = CachedMessageStatus::ReceivedMustConfirm; - } - message.pcd = Some(pcd); - message.pcd_cipher = None; } 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.prd_cipher = Some(cipher_msg); + new_msg.cipher.push(cipher_msg); messages.push(new_msg.clone()); return Ok(new_msg); } @@ -741,344 +545,102 @@ pub fn get_available_amount() -> ApiResult { pub struct createTransactionReturn { pub txid: String, pub transaction: String, - pub new_network_msg: CachedMessage, + pub new_messages: Vec +} + +#[derive(Debug, Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct CreateProcessInitTransactionArguments{ + pub member2fields: HashMap>, + pub process: Process, + pub stringified_pcd: String, // must be valid json } -/// This is what we call to answer a confirmation as a sender #[wasm_bindgen] -pub fn answer_confirmation_transaction( - message_id: u32, +pub fn create_process_init_transaction( + args: CreateProcessInitTransactionArguments, fee_rate: u32, ) -> ApiResult { - let mut messages = lock_messages()?; - let message: &mut CachedMessage; - if let Some(m) = messages.iter_mut().find(|m| m.id == message_id) { - if m.sender.is_none() || m.commited_in.is_none() { - return Err(ApiError { - message: "Invalid network message".to_owned(), + if args.member2fields.len() == 0 { + return Err(ApiError { + message: "Must have at least one recipient".to_owned(), + }); + } + + let pcd: Map; + if let Some(object) = Value::from_str(&args.stringified_pcd)?.as_object() { + pcd = object.to_owned(); + } else { + return Err(ApiError { + message: "provided pcd is not a valid json".to_owned(), + }); + } + + let mut process = args.process; + + // process doesn't have an initial state at this stage + if process.init_state != Value::Null { + return Err(ApiError { + message: "new process must have a null initial state".to_owned(), + }); + } + + // maybe the process script can embed some basic checks for the pcd, for example `pcd.members.len() == 1` + + let all_members: Vec<&Member> = args.member2fields.keys().collect(); + let nb_recipients = all_members.len(); + + let mut recipients: Vec = Vec::with_capacity(nb_recipients*2); + // we actually have 2 "recipients" in a technical sense for each social recipient + // that's necessary because we don't want to miss a notification because we don't have a device atm + for member in all_members { + let (address_a, address_b) = member.get_addresses(); + for sp_address in [address_a, address_b].into_iter() { + recipients.push(Recipient { + address: sp_address.into(), + amount: DEFAULT_AMOUNT, + nb_outputs: 1, }); } + } - message = m; - } else { + let mut fields2keys = Map::new(); + let mut fields2cipher = Map::new(); + Value::from_str(&args.stringified_pcd).unwrap().encrypt_fields(&mut fields2keys, &mut fields2cipher); + + process.init_state = Value::Object(fields2cipher.clone()); + + let local_device = lock_local_device()?; + + let sp_wallet = local_device.get_wallet(); + + let latest_state = local_device.get_latest_state(); + if latest_state == Value::Null { return Err(ApiError { - message: format!("Can't find message for id {}", message_id), + message: "Device not paired, nor pairing".to_owned(), }); } - let sp_address: SilentPaymentAddress = - message.recipient.as_ref().unwrap().as_str().try_into()?; - - let local_device = lock_local_device()?; - - let sp_wallet = local_device.get_wallet(); - - let recipient = Recipient { - address: sp_address.into(), - amount: DUST_THRESHOLD, - nb_outputs: 1, - }; - - let confirmed_by = message.confirmed_by.as_ref().unwrap(); - - let mut freezed_utxos = lock_freezed_utxos()?; - - // we remove the outpoint we want to spend from our freezed utxos list - freezed_utxos.remove(&confirmed_by); - - let signed_psbt = create_transaction( - &vec![confirmed_by], - &freezed_utxos, - sp_wallet, - vec![recipient], - None, - Amount::from_sat(fee_rate.into()), - message.recipient.clone(), + let sender: Member = serde_json::from_value( + latest_state.get("members") + .unwrap() + .as_array() + .ok_or(ApiError { message: "members must be an array".to_owned() })? + .get(0) + .ok_or(ApiError { message: "empty array".to_owned() })? + .clone() + )?; + + // We first generate the prd with all the keys that we will keep to ourselves + let full_prd = Prd::new( + PrdType::Init, + Uuid::from_str(&process.uuid).expect("We can trust process to have a valid uuid"), + serde_json::to_string(&sender)?, + fields2cipher.clone(), + fields2keys.clone() )?; - let final_tx = signed_psbt.extract_tx()?; - - message.status = CachedMessageStatus::Trusted; - - Ok(createTransactionReturn { - txid: final_tx.txid().to_string(), - transaction: serialize(&final_tx).to_lower_hex_string(), - new_network_msg: message.clone(), - }) -} - -/// This is what we call to confirm as a receiver -#[wasm_bindgen] -pub fn create_confirmation_transaction( - message_id: u32, - fee_rate: u32, -) -> ApiResult { - let mut messages = lock_messages()?; - let message: &mut CachedMessage; - if let Some(m) = messages.iter_mut().find(|m| m.id == message_id) { - if m.sender.is_none() || m.commited_in.is_none() || m.prd.is_none() { - return Err(ApiError { - message: "Invalid network message".to_owned(), - }); - } - - message = m; - } else { - return Err(ApiError { - message: format!("Can't find message for id {}", message_id), - }); - } - - let sp_address: SilentPaymentAddress = message.sender.as_ref().unwrap().as_str().try_into()?; - - let local_device = lock_local_device()?; - - let sp_wallet = local_device.get_wallet(); - - let recipient = Recipient { - address: sp_address.into(), - amount: DUST_THRESHOLD, - nb_outputs: 1, - }; - - let commited_in = message.commited_in.as_ref().unwrap(); - - let mut freezed_utxos = lock_freezed_utxos()?; - - // we remove the outpoint we want to spend from our freezed utxos list - freezed_utxos.remove(&commited_in); - - let signed_psbt = create_transaction( - &vec![commited_in], - &freezed_utxos, - &sp_wallet, - vec![recipient], - None, - Amount::from_sat(fee_rate.into()), - message.sender.clone(), - )?; - - // what's the vout of the output sent to sender? - let sp_address2vouts = map_outputs_to_sp_address(&signed_psbt.to_string())?; - let recipients_vouts = sp_address2vouts - .get::(&sp_address.into()) - .expect("recipients didn't change") - .as_slice(); - - let final_tx = signed_psbt.extract_tx()?; - - message.confirmed_by = Some(OutPoint { - txid: final_tx.txid(), - vout: recipients_vouts[0] as u32, - }); - - Ok(createTransactionReturn { - txid: final_tx.txid().to_string(), - transaction: serialize(&final_tx).to_lower_hex_string(), - new_network_msg: message.clone(), - }) -} - -#[wasm_bindgen] -pub fn create_login_transaction(fee_rate: u32) -> ApiResult { - // First thing is to check that all the revokation outpoints are still unspent - // We assume it has been checked before calling this function - let local_device = lock_local_device()?; - if !local_device.is_linked() { - return Err(ApiError { - message: "No linked device".to_owned(), - }); - } - - let sp_wallet = local_device.get_wallet(); - let paired_device = local_device.get_paired_device_info().unwrap(); - - let mut outpoint_to_spend = local_device.get_next_output_to_spend(); - - if outpoint_to_spend == OutPoint::default() { - // First login - outpoint_to_spend = OutPoint::new( - Txid::from_byte_array(paired_device.incoming_pairing_transaction), - 0, - ); - } - - let pcd = Pcd::new("LOGIN".to_owned()); - let pcd_commitment = sha256sum(pcd.to_string().as_bytes()); - - let key: [u8; 32] = Aes256Gcm::generate_key(thread_rng()).into(); - - let process = Process::new( - "empty".to_owned(), - vec![], - ValidationRules::new(0.0, Role::User), - Txid::all_zeros(), - String::default(), - String::default(), - String::default(), - Value::Null - ); - - let prd = Prd::new( - PrdType::Message, - process, - local_device - .get_wallet() - .get_client() - .get_receiving_address() - .try_into() - .unwrap(), - key, - pcd_commitment, - )?; - - let pcd_cipher = prd.encrypt_pcd(&pcd)?; - - let commitment = sha256sum(prd.to_string().as_bytes()); - - let recipient_address = SilentPaymentAddress::try_from(paired_device.address.as_str()).unwrap(); - - let recipient = Recipient { - address: recipient_address.into(), - amount: Amount::from_sat(1200), - nb_outputs: 1, - }; - - let mut freezed_utxos = lock_freezed_utxos()?; - - // we remove the outpoint we want to spend from our freezed utxos list - freezed_utxos.remove(&outpoint_to_spend); - - let signed_psbt = create_transaction( - &vec![&outpoint_to_spend], - &freezed_utxos, - sp_wallet, - vec![recipient], - Some(commitment.as_byte_array().to_vec()), - Amount::from_sat(fee_rate.into()), - None, - )?; - - let partial_secret = sp_wallet - .get_client() - .get_partial_secret_from_psbt(&signed_psbt)?; - - let shared_point = sp_utils::sending::calculate_ecdh_shared_secret( - &recipient_address.get_scan_key(), - &partial_secret, - ); - - let shared_secret = AnkSharedSecret::new(shared_point); - - let cipher = encrypt_with_key( - prd.to_string(), - shared_secret.to_byte_array().to_lower_hex_string(), - )?; - - // update our cache - let sp_address2vouts = map_outputs_to_sp_address(&signed_psbt.to_string())?; - let recipients_vouts = sp_address2vouts - .get::(&recipient_address.into()) - .expect("recipients didn't change") - .as_slice(); - - let final_tx = signed_psbt.extract_tx()?; - - let mut new_msg = CachedMessage::new(); - new_msg.sender = Some(prd.sender.clone()); - new_msg.pcd = Some(pcd); - new_msg.pcd_cipher = Some(pcd_cipher.to_lower_hex_string()); - new_msg.prd = Some(prd); - new_msg.prd_cipher = Some(cipher); - new_msg.commitment = Some(commitment.to_string()); - new_msg.commited_in = Some(OutPoint { - txid: final_tx.txid(), - vout: recipients_vouts[0] as u32, - }); - new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); - new_msg.recipient = Some(recipient_address.into()); - new_msg.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself - new_msg.status = CachedMessageStatus::Login; - lock_messages()?.push(new_msg.clone()); - - return Ok(createTransactionReturn { - txid: final_tx.txid().to_string(), - transaction: serialize(&final_tx).to_lower_hex_string(), - new_network_msg: new_msg, - }); -} - -#[wasm_bindgen] -pub fn create_pairing_transaction( - address: String, - fee_rate: u32, -) -> ApiResult { - let my_address = lock_local_device()? - .get_wallet() - .get_client() - .get_receiving_address(); - - let pcd = Pcd::new("PAIRING".to_owned()); - - let process = Process::new( - "empty".to_owned(), - vec![], - ValidationRules::new(0.0, Role::User), - Txid::all_zeros(), - String::default(), - String::default(), - String::default(), - Value::Null - ); - - let mut res = create_notification_transaction(address, process, pcd, fee_rate)?; - - let mut messages = lock_messages()?; - - if let Some(m) = messages.iter_mut().find(|m| m.id == res.new_network_msg.id) { - m.status = CachedMessageStatus::Pairing; - res.new_network_msg = m.clone(); - } else { - unreachable!("We don't have in cache the message we just created"); - } - - Ok(res) -} - -#[wasm_bindgen] -pub fn create_notification_transaction( - address: String, - process: Process, - pcd: Pcd, - fee_rate: u32, -) -> ApiResult { - let sp_address: SilentPaymentAddress = address.as_str().try_into()?; - - let local_device = lock_local_device()?; - - let sp_wallet = local_device.get_wallet(); - - let recipient = Recipient { - address: sp_address.into(), - amount: Amount::from_sat(1200), - nb_outputs: 1, - }; - - let pcd_commitment = sha256sum(pcd.to_string().as_bytes()); - - let key: [u8; 32] = Aes256Gcm::generate_key(thread_rng()).into(); - - let prd = Prd::new( - PrdType::Message, - process, - sp_wallet.get_client().get_receiving_address().try_into().unwrap(), - key, - pcd_commitment - )?; - - let prd_commitment = sha256sum(prd.to_string().as_bytes()); - - let pcd_cipher = prd.encrypt_pcd(&pcd)?; + let prd_commitment = full_prd.create_commitment(); let freezed_utxos = lock_freezed_utxos()?; @@ -1086,58 +648,76 @@ pub fn create_notification_transaction( &vec![], &freezed_utxos, sp_wallet, - vec![recipient], + recipients, Some(prd_commitment.as_byte_array().to_vec()), Amount::from_sat(fee_rate.into()), None, )?; + let sp_address2vouts = map_outputs_to_sp_address(&signed_psbt.to_string())?; + let partial_secret = sp_wallet .get_client() - .get_partial_secret_from_psbt(&signed_psbt)?; + .get_partial_secret_from_psbt(&signed_psbt)?; - let shared_point = sp_utils::sending::calculate_ecdh_shared_secret( - &sp_address.get_scan_key(), - &partial_secret, - ); - - let shared_secret = AnkSharedSecret::new(shared_point); - - let cipher = encrypt_with_key( - serde_json::to_string(&prd)?, - shared_secret.to_byte_array().to_lower_hex_string(), - )?; - - // update our cache - let sp_address2vouts = map_outputs_to_sp_address(&signed_psbt.to_string())?; - let recipients_vouts = sp_address2vouts - .get::(&address) - .expect("recipients didn't change") - .as_slice(); - // for now let's just take the smallest vout that belongs to the recipient let final_tx = signed_psbt.extract_tx()?; - let mut new_msg = CachedMessage::new(); - new_msg.sender = Some(prd.sender.clone()); - new_msg.prd = Some(prd); - new_msg.prd_cipher = Some(cipher); - new_msg.pcd = Some(pcd); - new_msg.pcd_cipher = Some(pcd_cipher.to_lower_hex_string()); - new_msg.commitment = Some(prd_commitment.as_byte_array().to_lower_hex_string()); - new_msg.commited_in = Some(OutPoint { - txid: final_tx.txid(), - vout: recipients_vouts[0] as u32, + let mut new_messages = vec![]; + let mut shared_secrets = vec![]; // This is a bit ugly, but this way we can update the process status + for (member, visible_fields) in args.member2fields { + let mut prd = full_prd.clone(); + prd.filter_keys(visible_fields); + let prd_msg = prd.to_network_msg(sp_wallet)?; + let mut res = CachedMessage::new(); + res.recipient = Some(member.clone()); + res.prd = Some(prd_msg.clone()); + res.sender = Some(sender.clone()); + res.pcd = Some(Value::Object(pcd.clone())); + res.commitment = Some(prd_commitment.to_string()); + res.status = CachedMessageStatus::Opened; + + let (addresses1, addresses2) = member.get_addresses(); + for sp_address in [addresses1, addresses2].into_iter() { + let shared_point = sp_utils::sending::calculate_ecdh_shared_secret( + &::try_from(sp_address).unwrap().get_scan_key(), + &partial_secret, + ); + + let shared_secret = AnkSharedSecret::new(shared_point).to_byte_array().to_lower_hex_string(); + + let cipher = encrypt_with_key( + prd_msg.clone(), + shared_secret.clone(), + )?; + res.cipher.push(cipher); + res.shared_secrets.push(shared_secret.clone()); + shared_secrets.push(shared_secret); + } + + new_messages.push(res); + } + + lock_messages()?.extend(new_messages.clone()); + + let mut processes = lock_processes()?; + let init_state = ProcessState { + commited_in: OutPoint::null(), + encrypted_pcd: Value::Object(fields2cipher), + keys: fields2keys, + validation_token: vec![] + }; + + // We are initializing a process, so we shouldn't have it in our cache yet + processes.insert(Uuid::parse_str(&process.uuid).unwrap(), RelevantProcess { + process, + states: vec![init_state], + current_status: ProcessStatus::Active(shared_secrets) }); - new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); - new_msg.recipient = Some(address); - new_msg.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself - new_msg.status = CachedMessageStatus::SentWaitingConfirmation; - lock_messages()?.push(new_msg.clone()); - Ok(createTransactionReturn { - txid: final_tx.txid().to_string(), - transaction: serialize(&final_tx).to_lower_hex_string(), - new_network_msg: new_msg, + Ok(createTransactionReturn { + txid: final_tx.txid().to_string(), + transaction: serialize(&final_tx).to_lower_hex_string(), + new_messages }) } @@ -1218,25 +798,7 @@ pub fn create_faucet_msg() -> ApiResult { let faucet_msg = FaucetMessage::new(sp_address.clone()); - let mut cached_msg = CachedMessage::new(); - cached_msg.recipient = Some(sp_address); - cached_msg.commitment = Some(faucet_msg.commitment.clone()); - cached_msg.status = CachedMessageStatus::FaucetWaiting; - lock_messages()?.push(cached_msg.clone()); - let network_msg = Envelope::new(AnkFlag::Faucet, &faucet_msg.to_string()); Ok(network_msg.to_string()) } - -fn sha256sum(input: &[u8]) -> sha256::Hash { - let mut engine = sha256::HashEngine::default(); - engine.write_all(&input); - sha256::Hash::from_engine(engine) -} - -#[wasm_bindgen] -pub fn create_commitment(payload_to_hash: String) -> String { - let hash = sha256sum(payload_to_hash.as_bytes()); - hash.to_byte_array().to_lower_hex_string() -} diff --git a/src/lib.rs b/src/lib.rs index 4661ad5..6e38363 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,9 +2,15 @@ use anyhow::Error; use sdk_common::crypto::AnkSharedSecret; use sdk_common::network::CachedMessage; +use sdk_common::process::Process; +use sdk_common::sp_client::bitcoin::OutPoint; +use sdk_common::uuid::Uuid; +use sdk_common::prd::ValidationToken; use serde::{Deserialize, Serialize}; +use serde_json::{Value, Map}; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; +use std::ops::Index; use std::sync::{Mutex, MutexGuard, OnceLock}; use tsify::Tsify; @@ -21,6 +27,45 @@ pub fn lock_messages() -> Result>, Error> .lock_anyhow() } +#[derive(Debug)] +pub enum ProcessStatus { + Sealed, + Active(Vec), // shared_secrets used to communicate on current session +} + +#[derive(Debug, Clone)] +pub struct ProcessState { + pub commited_in: OutPoint, + pub encrypted_pcd: Value, + pub keys: Map, // We may not always have all the keys + pub validation_token: Vec // This signs the encrypted pcd +} + +#[derive(Debug)] +pub struct RelevantProcess { + process: Process, + states: Vec, + current_status: ProcessStatus, +} + +impl RelevantProcess { + pub fn get_process(&self) -> Process { + self.process.clone() + } + + pub fn get_status_at(&self, index: usize) -> Option { + self.states.get(index).cloned() + } +} + +pub static CACHEDPROCESSES: OnceLock>> = OnceLock::new(); + +pub fn lock_processes() -> Result>, Error> { + CACHEDPROCESSES + .get_or_init(|| Mutex::new(HashMap::new())) + .lock_anyhow() +} + pub(crate) trait MutexExt { fn lock_anyhow(&self) -> Result, Error>; } diff --git a/src/process.rs b/src/process.rs deleted file mode 100644 index f9d7692..0000000 --- a/src/process.rs +++ /dev/null @@ -1,405 +0,0 @@ -use std::fmt::DebugStruct; - -use sdk_common::sp_client::silentpayments::utils::SilentPaymentAddress; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; -use tsify::Tsify; -use wasm_bindgen::prelude::*; - -pub const HTML_KOTPART: &str = " -
-
-

Send encrypted messages

- -
-
- - -
- - -
- -
-
- "; - -pub const HTML_STORAGE: &str = " -
-
-

Send encrypted messages

- -
-
- - -
- - -
- -
-
- "; - -pub const HTML_MESSAGING: &str = " -
-
-

Send encrypted messages

- -
-
-
- - -
- - -
- -
-
- "; - -pub const CSS: &str = " - body { - margin: 0; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - min-height: 100vh; - background-color: #f4f4f4; - font-family: 'Arial', sans-serif; - } - .container { - text-align: center; - } - .card { - max-width: 400px; - width: 100%; - padding: 20px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - background-color: #ffffff; - border-radius: 8px; - text-align: left; - overflow: hidden; - } - form { - display: flex; - flex-direction: column; - /* flex-wrap: wrap; */ - } - label { - font-weight: bold; - margin-bottom: 8px; - } - hr { - border: 0; - height: 1px; - background-color: #ddd; - margin: 10px 0; - } - input, select { - width: 100%; - padding: 10px; - margin: 8px 0; - box-sizing: border-box; - } - select { - padding: 10px; - background-color: #f9f9f9; - border: 1px solid #ddd; - border-radius: 4px; - cursor: pointer; - } - button { - display: inline-block; - background-color: #4caf50; - color: #fff; - border: none; - padding: 12px 17px; - border-radius: 4px; - cursor: pointer; - } - button:hover { - background-color: #45a049; - } - .side-by-side { - display: flex; - align-items: center; - justify-content: space-between; - } - .side-by-side>* { - display: inline-block; - } - button.recover { - display: inline-block; - text-align: center; - text-decoration: none; - display: inline-block; - background-color: #4caf50; - color: #fff; - border: none; - padding: 12px 17px; - border-radius: 4px; - cursor: pointer; - } - button.recover:hover { - background-color: #45a049; - } - a.btn { - display: inline-block; - text-align: center; - text-decoration: none; - display: inline-block; - background-color: #4caf50; - color: #fff; - border: none; - padding: 12px 17px; - border-radius: 4px; - cursor: pointer; - } - - a.btn:hover { - background-color: #45a049; - } - - a { - text-decoration: none; - color: #78a6de; - } - .bg-secondary { - background-color: #2b81ed; - } - .bg-primary { - background-color: #1A61ED; - } - .bg-primary:hover { - background-color: #457be8; - } - .card-revoke { - display: flex; - flex-direction: column; - max-width: 400px; - width: 100%; - padding: 20px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - background-color: #ffffff; - border-radius: 8px; - text-align: center; - align-items: center; - overflow: hidden; - } - .card-revoke a { - max-width: 50px; - width: 100%; - background: none; - border: none; - cursor: pointer; - } - .card-revoke button { - max-width: 200px; - width: 100%; - background: none; - border: none; - cursor: pointer; - color: #78a6de; - } - .card-revoke svg { - width: 100%; - height: auto; - fill: #333; - } - .image-label { - display: block; - color: #fff; - padding: 5px; - margin-top: 10px; - } - .image-container { - width: 400px; - height: 300px; - overflow: hidden; - } - .image-container img { - text-align: center; - width: 100%; - height: 100%; - object-fit: cover; - object-position: center center; - } - .passwordalert { - color: #FF0000; - } - "; - -pub const CSSUPDATE: &str = " - - "; - -pub const JSUPDATE: &str = " - var addSpAddressBtn = document.getElementById('add-sp-address-btn'); - var removeSpAddressBtn = document.querySelectorAll('.minus-sp-address-btn'); - - addSpAddressBtn.addEventListener('click', function (event) { - addDynamicField(this); - }); - - function addDynamicField(element) { - var addSpAddressBlock = document.getElementById('sp-address-block'); - var spAddress = addSpAddressBlock.querySelector('#sp-address').value; - addSpAddressBlock.querySelector('#sp-address').value = ''; - spAddress = spAddress.trim(); - if (spAddress != '') { - var sideBySideDiv = document.createElement('div'); - sideBySideDiv.className = 'side-by-side'; - - var inputElement = document.createElement('input'); - inputElement.type = 'text'; - inputElement.name = 'spAddresses[]'; - inputElement.setAttribute('form', 'no-form'); - inputElement.value = spAddress; - inputElement.disabled = true; - - var buttonElement = document.createElement('button'); - buttonElement.type = 'button'; - buttonElement.className = - 'circle-btn bg-secondary minus-sp-address-btn'; - buttonElement.innerHTML = '-'; - - buttonElement.addEventListener('click', function (event) { - removeDynamicField(this.parentElement); - }); - - sideBySideDiv.appendChild(inputElement); - sideBySideDiv.appendChild(buttonElement); - - addSpAddressBlock.appendChild(sideBySideDiv); - } - function removeDynamicField(element) { - element.remove(); - } - } - "; - -#[derive(Debug, Serialize, Deserialize, Default, Tsify)] -#[tsify(into_wasm_abi, from_wasm_abi)] -pub struct Process { - pub id: u32, - pub name: String, - pub version: String, - pub members: Vec, - pub html: String, - pub style: String, - pub script: String, - // Add conditions : process, member, peer, artefact -} diff --git a/src/user.rs b/src/user.rs index 2f8b11d..360f02f 100644 --- a/src/user.rs +++ b/src/user.rs @@ -9,6 +9,7 @@ use sdk_common::sp_client::bitcoin::{ Network, OutPoint, ScriptBuf, Transaction, Txid, XOnlyPublicKey, }; use sdk_common::sp_client::spclient::SpClient; +use sdk_common::uuid::Uuid; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use tsify::Tsify; diff --git a/src/wallet.rs b/src/wallet.rs index 6114274..c82f079 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -33,7 +33,7 @@ pub fn generate_sp_wallet(label: Option, network: Network) -> anyhow::Re network, )?; let our_address: SilentPaymentAddress = sp_client.get_receiving_address().try_into()?; - log::info!( + sdk_common::log::info!( "Created client for sp with address: {}", our_address.to_string() ); diff --git a/tests/challenge.rs b/tests/challenge.rs deleted file mode 100644 index 5750aa2..0000000 --- a/tests/challenge.rs +++ /dev/null @@ -1,153 +0,0 @@ -use std::collections::HashMap; - -use log::debug; -use sdk_client::api::{ - create_confirmation_transaction, create_notification_transaction, dump_device, dump_message_cache, get_outputs, reset_device, restore_device, set_message_cache, setup -}; -use sdk_common::network::{ - CachedMessage, CachedMessageStatus, Pcd -}; -use sdk_common::sp_client::bitcoin::OutPoint; -use sdk_common::sp_client::spclient::OwnedOutput; - -use tsify::JsValueSerdeExt; -use wasm_bindgen_test::*; - -wasm_bindgen_test_configure!(run_in_browser); - -mod utils; - -use utils::*; - -#[wasm_bindgen_test] -fn test_bob_challenges_alice() { - reset_device().unwrap(); - debug!("==============================================\nStarting test_bob_challenges_alice\n=============================================="); - - // =============================== Bob - setup(); - restore_device(BOB_CHALLENGE_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(BOB_CHALLENGE_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - let notification_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - debug!("Bob sends a challenge transaction back to Alice"); - debug!("outpoints: {:?}", bob_outputs); - let confirmation_tx = create_confirmation_transaction(notification_msg.id, 1).unwrap(); - - let confirmation_tweak_data = helper_get_tweak_data( - &confirmation_tx.transaction, - bob_outputs - ); - - debug!("Bob parsing its own confirmation tx"); - helper_parse_transaction( - &confirmation_tx.transaction, - &confirmation_tweak_data, - ); - - // ========================== Alice - reset_device().unwrap(); - restore_device(ALICE_CHALLENGE_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(ALICE_CHALLENGE_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - debug!("Alice parsing confirmation tx"); - helper_parse_transaction(&confirmation_tx.transaction, &confirmation_tweak_data); -} - -// #[wasm_bindgen_test] -// fn test_alice_answers_bob() { -// reset_device().unwrap(); -// setup(); -// debug!("==============================================\nStarting test_alice_answers_bob\n=============================================="); -// restore_device(ALICE_ANSWER_DEVICE.to_owned()).unwrap(); -// set_message_cache( -// serde_json::from_str::>(ALICE_ANSWER_CACHE) -// .unwrap() -// .into_iter() -// .map(|v| v.to_string()) -// .collect(), -// ) -// .unwrap(); - -// let challenge_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); - -// debug!("Alice answers bob's challenge"); -// let answer_tx = answer_confirmation_transaction(challenge_msg.id, 1).unwrap(); - -// let get_outputs_result = get_outputs().unwrap(); - -// let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - -// let answer_tweak_data = helper_get_tweak_data( -// &answer_tx.transaction, -// alice_outputs, -// ); - -// debug!("Alice parses her own transaction"); -// helper_parse_transaction(&answer_tx.transaction, &answer_tweak_data); - -// reset_device().unwrap(); -// restore_device(BOB_ANSWER_DEVICE.to_owned()).unwrap(); - -// set_message_cache( -// serde_json::from_str::>(BOB_ANSWER_CACHE) -// .unwrap() -// .into_iter() -// .map(|v| v.to_string()) -// .collect(), -// ) -// .unwrap(); - -// debug!("Bob parses answer transaction {}", answer_tx.txid); -// helper_parse_transaction(&answer_tx.transaction, &answer_tweak_data); -// } - -// #[wasm_bindgen_test] -// fn test_alice_sends_message_through_trusted_channel() { -// reset_device().unwrap(); -// setup(); -// debug!("==============================================\nStarting test_alice_sends_message_through_trusted_channel\n=============================================="); - -// restore_device(ALICE_FINAL_DEVICE.to_owned()).unwrap(); - -// set_message_cache( -// serde_json::from_str::>(ALICE_FINAL_CACHE) -// .unwrap() -// .into_iter() -// .map(|v| v.to_string()) -// .collect(), -// ) -// .unwrap(); - -// let answered_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap(); - -// // Bob sends a message to Alice -// debug!("Bob Sends a message to Alice"); -// let secret_msg = "Hello Alice"; -// let cipher = -// encrypt_with_key(secret_msg.to_owned(), answered_msg.shared_secret.unwrap()).unwrap(); -// let bob_msg = Envelope::new(sdk_common::network::AnkFlag::Cipher, &cipher); - -// // Alice can find the message -// let mut result = helper_parse_cipher(bob_msg.to_string()); -// assert!(result.plaintext.pop() == Some(secret_msg.to_owned())); -// } \ No newline at end of file diff --git a/tests/pairing.rs b/tests/pairing.rs index d3686d0..ca94b08 100644 --- a/tests/pairing.rs +++ b/tests/pairing.rs @@ -1,15 +1,18 @@ use std::collections::HashMap; -use log::debug; use sdk_client::api::{ - create_login_transaction, create_pairing_transaction, dump_device, dump_message_cache, dump_wallet, get_outputs, login, pair_device, reset_device, restore_device, set_message_cache, setup -}; -use sdk_common::network::{ - CachedMessage, CachedMessageStatus, + create_device_from_sp_wallet, create_process_init_transaction, get_outputs, pair_device, reset_device, setup, CreateProcessInitTransactionArguments }; +use sdk_client::lock_processes; +use sdk_common::network::CachedMessage; +use sdk_common::pcd::{Member, Pcd, Role}; +use sdk_common::prd::Prd; +use sdk_common::process::{Process, ValidationRules}; use sdk_common::sp_client::bitcoin::OutPoint; use sdk_common::sp_client::spclient::OwnedOutput; -use serde_json; +use sdk_common::uuid::Uuid; +use sdk_common::log::debug; +use serde_json::{self, json, Value}; use tsify::JsValueSerdeExt; use wasm_bindgen_test::*; @@ -26,229 +29,119 @@ fn test_pairing() { debug!("==============================================\nStarting test_pairing\n=============================================="); // ========================= Alice - helper_switch_device(ALICE_LOGIN_WALLET.to_owned()); + reset_device().unwrap(); + create_device_from_sp_wallet(ALICE_LOGIN_WALLET.to_owned()).unwrap(); - debug!("Alice sends a pairing transaction to Bob"); - let alice_pairing_tx = create_pairing_transaction(helper_get_bob_address(), 1).unwrap(); + // Alice creates the new member with Bob address + let new_member = Member::new( + DEFAULT_NYM.to_owned(), + helper_get_alice_address().try_into().unwrap(), + helper_get_bob_address().try_into().unwrap(), + Role::User + ); + + let initial_state = json!({ + "nym": DEFAULT_NYM, + "members": [ + new_member, + ], + "current_session_tx": null, + }); + + let validation_rules = ValidationRules::new( + 1.0, + Role::Admin, + 1.0 + ); + + let mut member2fields: HashMap> = HashMap::new(); + member2fields.insert(new_member, initial_state.as_object().unwrap().keys().map(|k| k.to_owned()).collect()); + + // We define the process for pairing + let pairing_process = Process::new( + "pairing".to_owned(), + validation_rules, + String::default(), + String::default(), + String::default(), + Value::Null, + OutPoint::null() + ); + + // we can update our local device now + pair_device(pairing_process.uuid.clone(), helper_get_bob_address(), initial_state.to_string()).unwrap(); + + debug!("Alice sends a transaction commiting to an init prd to Bob"); + let args = CreateProcessInitTransactionArguments { + member2fields, + process: pairing_process, + stringified_pcd: initial_state.to_string() + }; + let alice_pairing_return = create_process_init_transaction(args, 1).unwrap(); let get_outputs_result = get_outputs().unwrap(); let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); let alice_pairing_tweak_data = - helper_get_tweak_data(&alice_pairing_tx.transaction, alice_outputs); + helper_get_tweak_data(&alice_pairing_return.transaction, alice_outputs); // Alice parse her own transaction - let alice_msg_id = - helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data).id; - - let alice_wallet = dump_wallet().unwrap(); - let alice_cache = dump_message_cache().unwrap(); + helper_parse_transaction(&alice_pairing_return.transaction, &alice_pairing_tweak_data).id; // ======================= Bob reset_device().unwrap(); - helper_switch_device(BOB_LOGIN_WALLET.to_owned()); + create_device_from_sp_wallet(BOB_LOGIN_WALLET.to_owned()).unwrap(); // Bob receives Alice pairing transaction - // if he agrees, he must send another pairing transaction to Alice - // he can also spend the output that notified him that will become Alice first session key debug!("Bob parses Alice pairing transaction"); - helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data); + helper_parse_transaction(&alice_pairing_return.transaction, &alice_pairing_tweak_data); debug!("Bob receives the prd"); - helper_parse_cipher(alice_pairing_tx.new_network_msg.prd_cipher.unwrap()); + let mut bob_retrieved_prd = CachedMessage::default(); + for message in alice_pairing_return.new_messages.iter() { + for cipher in message.cipher.iter() { + match helper_parse_cipher(cipher.clone()) { + Ok(res) => bob_retrieved_prd = res, + Err(_) => continue + } + } + } + + if bob_retrieved_prd == CachedMessage::default() { + panic!("Bob failed to retrieve Alice message"); + } debug!("Bob receives the pcd"); - let alice_pairing_res = helper_parse_cipher(alice_pairing_tx.new_network_msg.pcd_cipher.unwrap()); + let mut bob_retrieved_pcd = CachedMessage::default(); + for message in alice_pairing_return.new_messages { + for cipher in message.cipher { + match helper_parse_cipher(cipher) { + Ok(res) => bob_retrieved_pcd = res, + Err(_) => continue + } + } + } - assert!(alice_pairing_res.status == CachedMessageStatus::Pairing); - // Bob takes the txid of the incoming transaction from Alice, he will need it for pairing - let incoming_txid = alice_pairing_res.commited_in.unwrap().txid; + if bob_retrieved_pcd == CachedMessage::default() { + panic!("Bob failed to retrieve Alice message"); + } // At this point, user must validate the pairing proposal received from Alice - debug!("Bob sends a pairing transaction back"); - let bob_pairing_tx = create_pairing_transaction(alice_pairing_res.sender.unwrap(), 1).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let bob_pairing_tweak_data = helper_get_tweak_data(&bob_pairing_tx.transaction, bob_outputs); - - helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); - debug!("Bob pairs device with Alice"); - let pairing_process = pair_device(DEFAULT_NYM.to_owned(), bob_pairing_tx.new_network_msg.id, incoming_txid.to_string()).unwrap(); + let process = lock_processes().unwrap(); + let prd: Prd = serde_json::from_str(&bob_retrieved_prd.prd.unwrap()).unwrap(); + let relevant_process = process.get(&Uuid::parse_str(&prd.process_uuid).unwrap()).unwrap(); + // decrypt the pcd and update bob device + if let Some(initial_state) = relevant_process.get_status_at(0) { + let keys = initial_state.keys; + let mut pcd = initial_state.encrypted_pcd; + pcd.decrypt_fields(&keys).unwrap(); + pair_device(relevant_process.get_process().uuid, helper_get_alice_address(), pcd.to_string()).unwrap(); + } - // sign the pairing process + // To make the pairing effective, alice and bob must now spend their respective output into a new transaction - // send it to Alice so that she can sign it too - - // commit it to a transaction to make it public - - // ======================== Alice - reset_device().unwrap(); - helper_switch_device(alice_wallet); - set_message_cache(alice_cache).unwrap(); - - // parse Bob's pairing transaction - helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); - helper_parse_cipher(bob_pairing_tx.new_network_msg.prd_cipher.unwrap()); - - let bob_pairing_msg = helper_parse_cipher(bob_pairing_tx.new_network_msg.pcd_cipher.unwrap()); - - assert!(bob_pairing_msg.status == CachedMessageStatus::Pairing); - - debug!("Alice pairs device"); - pair_device(DEFAULT_NYM.to_owned(), alice_msg_id, bob_pairing_tx.txid).unwrap(); -} - -#[wasm_bindgen_test] -fn test_first_login() { - reset_device().unwrap(); - setup(); - debug!("==============================================\nStarting test_first_login\n=============================================="); - - restore_device(BOB_PAIRED_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(BOB_PAIRING_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - // Bob can now spend the notification output, that will become Alice's first session key - debug!("Bob first login"); - let bob_first_login_tx = create_login_transaction(1).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let bob_login_tweak_data = helper_get_tweak_data(&bob_first_login_tx.transaction, bob_outputs); - - debug!("Bob parses his own login transaction"); - helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data); - - let bob_device = dump_device().unwrap(); - let bob_cache = dump_message_cache().unwrap(); - - // ======================== Alice - reset_device().unwrap(); - restore_device(ALICE_PAIRED_DEVICE.to_owned()).unwrap(); - set_message_cache( - serde_json::from_str::>(ALICE_PAIRING_CACHE) - .unwrap() - .into_iter() - .map(|v| v.to_string()) - .collect(), - ) - .unwrap(); - - debug!("Alice finds out the login demand from Bob"); - helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data); - helper_parse_cipher(bob_first_login_tx.new_network_msg.prd_cipher.unwrap()); - let bob_login_msg = helper_parse_cipher(bob_first_login_tx.new_network_msg.pcd_cipher.unwrap()); - - // At this point Alice can fire up the revokation output if the login demand is illegitimate - // OR she must answer with a login transaction to Bob - debug!("Alice first login"); - let alice_first_login_tx = create_login_transaction(1).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let alice_login_tweak_data = - helper_get_tweak_data(&alice_first_login_tx.transaction, alice_outputs); - - helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data); - - login(bob_login_msg.id, alice_first_login_tx.transaction.clone()).unwrap(); - - // ======================= Bob - reset_device().unwrap(); - restore_device(bob_device).unwrap(); - set_message_cache(bob_cache).unwrap(); - - helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data); - helper_parse_cipher(alice_first_login_tx.new_network_msg.prd_cipher.unwrap()); - let alice_login_msg = helper_parse_cipher(alice_first_login_tx.new_network_msg.pcd_cipher.unwrap()); - - assert!(alice_login_msg.status == CachedMessageStatus::Login); - - login(alice_login_msg.id, bob_first_login_tx.transaction).unwrap(); -} - -#[wasm_bindgen_test] -fn test_login() { - reset_device().unwrap(); - setup(); - debug!("==============================================\nStarting test_login\n=============================================="); - - // ======================= Alice - restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap(); - - debug!("Alice sends a login transaction to Bob, which creates a new key for him"); - let alice_login_tx = create_login_transaction(1).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let alice_login_tweak_data = helper_get_tweak_data( - &alice_login_tx.transaction, - alice_outputs - ); - - debug!("Parsing Alice login transaction"); - helper_parse_transaction(&alice_login_tx.transaction, &alice_login_tweak_data); - - let alice_device = dump_device().unwrap(); - let alice_cache = dump_message_cache().unwrap(); - - // ============================== Bob - reset_device().unwrap(); - restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap(); - - debug!("Bob finds out the login demand from Alice"); - helper_parse_transaction(&alice_login_tx.transaction, &alice_login_tweak_data); - helper_parse_cipher(alice_login_tx.new_network_msg.prd_cipher.unwrap()); - let alice_login_msg = helper_parse_cipher(alice_login_tx.new_network_msg.pcd_cipher.unwrap()); - - // Bob must confirm that he agrees to log in - - // Boutons "login" ou "Refuser" - // At this point Bob can fire up the revokation output if the login demand is illegitimate - // revoke_paired_device(1).unwrap(); - // OR it must answer with a login transaction to Alice - let bob_login_tx = create_login_transaction(1).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let bob_login_tweak_data = helper_get_tweak_data(&bob_login_tx.transaction, bob_outputs); - - debug!("Bob parses his own login transaction"); - helper_parse_transaction(&bob_login_tx.transaction, &bob_login_tweak_data); - - login(alice_login_msg.id, alice_login_tx.transaction.clone()).unwrap(); - - // =================== Alice - - reset_device().unwrap(); - restore_device(alice_device).unwrap(); - set_message_cache(alice_cache).unwrap(); - - helper_parse_transaction(&bob_login_tx.transaction, &bob_login_tweak_data); - helper_parse_cipher(bob_login_tx.new_network_msg.prd_cipher.unwrap()); - let bob_login_msg = helper_parse_cipher(bob_login_tx.new_network_msg.pcd_cipher.unwrap()); - - assert!(bob_login_msg.status == CachedMessageStatus::Login); - - login(bob_login_msg.id, alice_login_tx.transaction).unwrap(); + // Once we know this tx id, we can commit to the relay } diff --git a/tests/prd.rs b/tests/prd.rs deleted file mode 100644 index 736d487..0000000 --- a/tests/prd.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::collections::HashMap; - -use log::debug; -use sdk_client::api::{ - create_confirmation_transaction, create_notification_transaction, dump_device, dump_message_cache, get_outputs, reset_device, restore_device, set_message_cache, setup -}; -use sdk_common::network::{ - CachedMessage, CachedMessageStatus, Pcd -}; -use sdk_common::process::{Process, Role, ValidationRules}; -use sdk_common::sp_client::bitcoin::hashes::Hash; -use sdk_common::sp_client::bitcoin::{OutPoint, Txid}; -use sdk_common::sp_client::spclient::OwnedOutput; - -use serde_json::Value; -use tsify::JsValueSerdeExt; -use wasm_bindgen_test::*; - -wasm_bindgen_test_configure!(run_in_browser); - -mod utils; - -use utils::*; - -#[wasm_bindgen_test] -fn test_alice_sends_prd_message_to_bob() { - reset_device().unwrap(); - setup(); - debug!("==============================================\nStarting test_alice_sends_prd_message_to_bob\n=============================================="); - - // ============================ Alice - restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap(); - - // Alice first puts her message in a pcd - let pcd = Pcd::new("TEST".to_owned()); - debug!("Alice notified Bob about a message it sent"); - - let empty_process = Process::new( - "empty".to_owned(), - vec![], - ValidationRules::new(0.0, Role::User), - Txid::all_zeros(), - String::default(), - String::default(), - String::default(), - Value::Null - ); - - let notification_tx = - create_notification_transaction(helper_get_bob_address(), empty_process, pcd, 1).unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - let notification_tweak_data = helper_get_tweak_data( - ¬ification_tx.transaction, - alice_outputs - ); - - debug!("Alice parses her own notification transaction"); - // Alice parse her own transaction to update her utxos - helper_parse_transaction( - ¬ification_tx.transaction, - ¬ification_tweak_data, - ); - - reset_device().unwrap(); - restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap(); - - debug!("bob parses the transaction and the message"); - helper_parse_transaction(¬ification_tx.transaction, ¬ification_tweak_data); - helper_parse_cipher(notification_tx.new_network_msg.prd_cipher.unwrap()); - let bob_notification_msg = helper_parse_cipher(notification_tx.new_network_msg.pcd_cipher.unwrap()); - - let msg_dump = dump_message_cache().unwrap(); - debug!("bob_wallet: {:?}", dump_device()); - debug!("bob_notification_msg: {:?}", msg_dump); - debug!("commited_in: {:?}", msg_dump.get(0).unwrap().find("0x71b37cede4655932a5ce97bb8c4a7845adce96d4f85b64bc699bf74942c19f89")); - - assert!(bob_notification_msg.status == CachedMessageStatus::ReceivedMustConfirm); -} diff --git a/tests/utils.rs b/tests/utils.rs index ed8e4d1..262c209 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; -use log::debug; -use sdk_client::api::{parse_cipher, parse_new_tx, reset_device, restore_device_from_sp_wallet}; +use sdk_client::api::{parse_cipher, parse_new_tx, reset_device, ApiResult}; use sdk_common::network::{ CachedMessage, NewTxMessage, }; @@ -13,6 +12,7 @@ use sdk_common::sp_client::silentpayments::utils::receiving::{ calculate_tweak_data, get_pubkey_from_input, }; use sdk_common::sp_client::spclient::{OwnedOutput, SpWallet}; +use sdk_common::log::debug; use serde_json; // We're using alice and bob for clarity, but it's important to remember that for pairing and login Alice and Bob are the same person @@ -39,11 +39,6 @@ pub const ALICE_FINAL_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"de pub const DEFAULT_NYM: &str = "AliceBob"; -pub fn helper_switch_device(wallet: String) { - reset_device().unwrap(); - restore_device_from_sp_wallet(wallet.clone()).unwrap(); -} - pub fn helper_get_alice_address() -> String { let wallet: SpWallet = serde_json::from_str(ALICE_START_WALLET).unwrap(); wallet.get_client().get_receiving_address() @@ -100,10 +95,6 @@ pub fn helper_parse_transaction(transaction: &str, tweak_data: &str) -> CachedMe } } -pub fn helper_parse_cipher(cipher_msg: String) -> CachedMessage { - let result = parse_cipher(cipher_msg, 1); - match result { - Ok(r) => return r, - Err(e) => panic!("Unexpected error: {}", e.message), - }; +pub fn helper_parse_cipher(cipher_msg: String) -> ApiResult { + parse_cipher(cipher_msg, 1) } From cf3278dd3d7689332337d52bbfa040676d2b253e Mon Sep 17 00:00:00 2001 From: Sosthene Date: Fri, 30 Aug 2024 20:02:47 +0200 Subject: [PATCH 05/14] Update process creation --- src/api.rs | 126 +++++++++++++++++++++-------------------------- tests/pairing.rs | 94 +++++++++++++++++++---------------- 2 files changed, 108 insertions(+), 112 deletions(-) diff --git a/src/api.rs b/src/api.rs index 6ee8900..3718dd2 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,6 +1,6 @@ use std::any::Any; use std::borrow::Borrow; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::io::Write; use std::ops::Index; use std::str::FromStr; @@ -15,7 +15,7 @@ use anyhow::Error as AnyhowError; use sdk_common::crypto::{ AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, AnkSharedSecret, KeyInit, Purpose, }; -use sdk_common::process::{Process, ValidationRules}; +use sdk_common::process::Process; use sdk_common::signature; use sdk_common::sp_client::bitcoin::blockdata::fee_rate; use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; @@ -52,7 +52,7 @@ use wasm_bindgen::prelude::*; use sdk_common::network::{ self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage}; -use sdk_common::pcd::{AnkPcdHash, Pcd, Member}; +use sdk_common::pcd::{AnkPcdHash, Member, Pcd, RoleDefinition, ValidationRule}; use sdk_common::prd::{AnkPrdHash, Prd, PrdType}; use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address}; use sdk_common::sp_client::spclient::{ @@ -222,7 +222,7 @@ pub fn create_new_device(birthday: u32, network_str: String) -> ApiResult ApiResult<()> { +pub fn pair_device(uuid: String, mut sp_addresses: Vec) -> ApiResult<()> { let mut local_device = lock_local_device()?; if local_device.is_linked() { @@ -231,9 +231,12 @@ pub fn pair_device(uuid: String, new_device_address: String, state: String) -> A }); } - local_device.set_process_uuid(Uuid::parse_str(&uuid).map_err(|e| ApiError { message: e.to_string() })?); - local_device.push_paired_device(new_device_address.try_into().map_err(|_| ApiError { message: "Invalid address".to_owned() })?); - local_device.update_latest_state(serde_json::from_str(&state)?); + sp_addresses.push(local_device.get_wallet().get_client().get_receiving_address()); + + local_device.pair( + Uuid::parse_str(&uuid).unwrap(), + Member::new(sp_addresses.into_iter().map(|a| TryInto::::try_into(a).unwrap()).collect())? + ); Ok(()) } @@ -539,6 +542,20 @@ pub fn get_available_amount() -> ApiResult { Ok(device.get_wallet().get_outputs().get_balance().to_sat()) } +#[wasm_bindgen] +pub fn create_process_from_template(json: String) -> ApiResult { + let template_process: Process = serde_json::from_str(&json)?; + let mut new_process = Process::new( + template_process.html, + template_process.style, + template_process.script, + template_process.init_state, + template_process.commited_in + ); + + Ok(new_process) +} + #[derive(Debug, Tsify, Serialize, Deserialize, Default)] #[tsify(into_wasm_abi, from_wasm_abi)] #[allow(non_camel_case_types)] @@ -548,54 +565,38 @@ pub struct createTransactionReturn { pub new_messages: Vec } -#[derive(Debug, Serialize, Deserialize, Tsify)] -#[tsify(into_wasm_abi, from_wasm_abi)] -pub struct CreateProcessInitTransactionArguments{ - pub member2fields: HashMap>, - pub process: Process, - pub stringified_pcd: String, // must be valid json -} - #[wasm_bindgen] pub fn create_process_init_transaction( - args: CreateProcessInitTransactionArguments, + mut new_process: Process, fee_rate: u32, ) -> ApiResult { - if args.member2fields.len() == 0 { - return Err(ApiError { - message: "Must have at least one recipient".to_owned(), - }); - } - - let pcd: Map; - if let Some(object) = Value::from_str(&args.stringified_pcd)?.as_object() { - pcd = object.to_owned(); - } else { - return Err(ApiError { - message: "provided pcd is not a valid json".to_owned(), - }); + let pcd = new_process.init_state; + let roles = pcd["roles"].as_object().unwrap().clone(); + let mut all_members: HashMap> = HashMap::new(); + for (name, role_def) in roles { + let role: RoleDefinition = serde_json::from_str(&role_def.to_string()).unwrap(); + let fields: Vec = role.validation_rules.iter().flat_map(|rule| rule.fields.clone()).collect(); + for member in role.members { + if !all_members.contains_key(&member) { + all_members.insert(member.clone(), HashSet::new()); + } + all_members.get_mut(&member).unwrap().extend(fields.clone()); + } } - let mut process = args.process; - - // process doesn't have an initial state at this stage - if process.init_state != Value::Null { - return Err(ApiError { - message: "new process must have a null initial state".to_owned(), - }); - } - - // maybe the process script can embed some basic checks for the pcd, for example `pcd.members.len() == 1` - - let all_members: Vec<&Member> = args.member2fields.keys().collect(); let nb_recipients = all_members.len(); + if nb_recipients == 0 { + return Err(ApiError { + message: "Can't create a process with 0 member".to_owned(), + }); + } - let mut recipients: Vec = Vec::with_capacity(nb_recipients*2); - // we actually have 2 "recipients" in a technical sense for each social recipient + let mut recipients: Vec = Vec::with_capacity(nb_recipients*2); // We suppose that will work most of the time + // we actually have multiple "recipients" in a technical sense for each social recipient // that's necessary because we don't want to miss a notification because we don't have a device atm - for member in all_members { - let (address_a, address_b) = member.get_addresses(); - for sp_address in [address_a, address_b].into_iter() { + for member in all_members.keys() { + let addresses = member.get_addresses(); + for sp_address in addresses.into_iter() { recipients.push(Recipient { address: sp_address.into(), amount: DEFAULT_AMOUNT, @@ -606,35 +607,20 @@ pub fn create_process_init_transaction( let mut fields2keys = Map::new(); let mut fields2cipher = Map::new(); - Value::from_str(&args.stringified_pcd).unwrap().encrypt_fields(&mut fields2keys, &mut fields2cipher); + Value::Object(pcd.clone()).encrypt_fields(&mut fields2keys, &mut fields2cipher); - process.init_state = Value::Object(fields2cipher.clone()); + new_process.init_state = fields2cipher.clone(); let local_device = lock_local_device()?; let sp_wallet = local_device.get_wallet(); - let latest_state = local_device.get_latest_state(); - if latest_state == Value::Null { - return Err(ApiError { - message: "Device not paired, nor pairing".to_owned(), - }); - } - - let sender: Member = serde_json::from_value( - latest_state.get("members") - .unwrap() - .as_array() - .ok_or(ApiError { message: "members must be an array".to_owned() })? - .get(0) - .ok_or(ApiError { message: "empty array".to_owned() })? - .clone() - )?; + let sender: Member = local_device.to_member().unwrap(); // We first generate the prd with all the keys that we will keep to ourselves let full_prd = Prd::new( PrdType::Init, - Uuid::from_str(&process.uuid).expect("We can trust process to have a valid uuid"), + Uuid::from_str(&new_process.uuid).expect("We can trust process to have a valid uuid"), serde_json::to_string(&sender)?, fields2cipher.clone(), fields2keys.clone() @@ -664,7 +650,7 @@ pub fn create_process_init_transaction( let mut new_messages = vec![]; let mut shared_secrets = vec![]; // This is a bit ugly, but this way we can update the process status - for (member, visible_fields) in args.member2fields { + for (member, visible_fields) in all_members { let mut prd = full_prd.clone(); prd.filter_keys(visible_fields); let prd_msg = prd.to_network_msg(sp_wallet)?; @@ -676,8 +662,8 @@ pub fn create_process_init_transaction( res.commitment = Some(prd_commitment.to_string()); res.status = CachedMessageStatus::Opened; - let (addresses1, addresses2) = member.get_addresses(); - for sp_address in [addresses1, addresses2].into_iter() { + let addresses = member.get_addresses(); + for sp_address in addresses.into_iter() { let shared_point = sp_utils::sending::calculate_ecdh_shared_secret( &::try_from(sp_address).unwrap().get_scan_key(), &partial_secret, @@ -708,8 +694,8 @@ pub fn create_process_init_transaction( }; // We are initializing a process, so we shouldn't have it in our cache yet - processes.insert(Uuid::parse_str(&process.uuid).unwrap(), RelevantProcess { - process, + processes.insert(Uuid::parse_str(&new_process.uuid).unwrap(), RelevantProcess { + process: new_process, states: vec![init_state], current_status: ProcessStatus::Active(shared_secrets) }); diff --git a/tests/pairing.rs b/tests/pairing.rs index ca94b08..252471b 100644 --- a/tests/pairing.rs +++ b/tests/pairing.rs @@ -1,18 +1,17 @@ use std::collections::HashMap; use sdk_client::api::{ - create_device_from_sp_wallet, create_process_init_transaction, get_outputs, pair_device, reset_device, setup, CreateProcessInitTransactionArguments + create_device_from_sp_wallet, create_process_from_template, create_process_init_transaction, get_address, get_outputs, pair_device, reset_device, setup }; use sdk_client::lock_processes; use sdk_common::network::CachedMessage; -use sdk_common::pcd::{Member, Pcd, Role}; +use sdk_common::pcd::{Member, Pcd}; use sdk_common::prd::Prd; -use sdk_common::process::{Process, ValidationRules}; use sdk_common::sp_client::bitcoin::OutPoint; use sdk_common::sp_client::spclient::OwnedOutput; use sdk_common::uuid::Uuid; use sdk_common::log::debug; -use serde_json::{self, json, Value}; +use serde_json::{self, json}; use tsify::JsValueSerdeExt; use wasm_bindgen_test::*; @@ -32,52 +31,60 @@ fn test_pairing() { reset_device().unwrap(); create_device_from_sp_wallet(ALICE_LOGIN_WALLET.to_owned()).unwrap(); + // we get our own address + let device_address = get_address().unwrap(); + + // we scan the qr code or get the address by any other means + let paired_device = helper_get_bob_address(); + // Alice creates the new member with Bob address let new_member = Member::new( - DEFAULT_NYM.to_owned(), - helper_get_alice_address().try_into().unwrap(), - helper_get_bob_address().try_into().unwrap(), - Role::User - ); + vec![ + device_address.as_str().try_into().unwrap(), + paired_device.as_str().try_into().unwrap(), + ] + ).unwrap(); - let initial_state = json!({ - "nym": DEFAULT_NYM, - "members": [ - new_member, - ], - "current_session_tx": null, + // We get the template for the pairing + // We don't really care how we get it, we can even imagine user writing it himself + // It just have to respect the basic Process struct, i.e. have all the fields below and the right type for the value + let pairing_template = json!({ + "uuid": "", + "html": "", + "script": "", + "style": "", + "init_state": { + "roles": { + "owner": { + "members": + [ + new_member + ], + "validation_rules": + [ + { + "quorum": 0.0, + "fields": [ + "roles", + "pairing_tx" + ], + "min_sig_member": 0.0 + } + ] + } + }, + "pairing_tx": "", + }, + "commited_in": OutPoint::null() }); - let validation_rules = ValidationRules::new( - 1.0, - Role::Admin, - 1.0 - ); - - let mut member2fields: HashMap> = HashMap::new(); - member2fields.insert(new_member, initial_state.as_object().unwrap().keys().map(|k| k.to_owned()).collect()); - - // We define the process for pairing - let pairing_process = Process::new( - "pairing".to_owned(), - validation_rules, - String::default(), - String::default(), - String::default(), - Value::Null, - OutPoint::null() - ); + let new_process = create_process_from_template(pairing_template.to_string()).unwrap(); // we can update our local device now - pair_device(pairing_process.uuid.clone(), helper_get_bob_address(), initial_state.to_string()).unwrap(); + pair_device(new_process.uuid.clone(), vec![helper_get_bob_address()]).unwrap(); debug!("Alice sends a transaction commiting to an init prd to Bob"); - let args = CreateProcessInitTransactionArguments { - member2fields, - process: pairing_process, - stringified_pcd: initial_state.to_string() - }; - let alice_pairing_return = create_process_init_transaction(args, 1).unwrap(); + let alice_pairing_return = create_process_init_transaction(new_process, 1).unwrap(); let get_outputs_result = get_outputs().unwrap(); @@ -89,6 +96,8 @@ fn test_pairing() { // Alice parse her own transaction helper_parse_transaction(&alice_pairing_return.transaction, &alice_pairing_tweak_data).id; + // Notify user that we're waiting for confirmation from the other device + // ======================= Bob reset_device().unwrap(); create_device_from_sp_wallet(BOB_LOGIN_WALLET.to_owned()).unwrap(); @@ -138,10 +147,11 @@ fn test_pairing() { let keys = initial_state.keys; let mut pcd = initial_state.encrypted_pcd; pcd.decrypt_fields(&keys).unwrap(); - pair_device(relevant_process.get_process().uuid, helper_get_alice_address(), pcd.to_string()).unwrap(); + pair_device(relevant_process.get_process().uuid, vec![device_address]).unwrap(); } // To make the pairing effective, alice and bob must now spend their respective output into a new transaction + // login(); // Once we know this tx id, we can commit to the relay } From b7bffe7678ee76fe011288124736f83a8265f3e5 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Mon, 2 Sep 2024 14:45:35 +0200 Subject: [PATCH 06/14] Add more error control --- src/api.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/api.rs b/src/api.rs index 3718dd2..221156d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -571,10 +571,11 @@ pub fn create_process_init_transaction( fee_rate: u32, ) -> ApiResult { let pcd = new_process.init_state; - let roles = pcd["roles"].as_object().unwrap().clone(); + let roles = pcd.get("roles").ok_or(ApiError { message: "No roles in init_state".to_owned()})?; + let roles_map = roles.as_object().ok_or(ApiError { message: "roles is not an object".to_owned()})?.clone(); let mut all_members: HashMap> = HashMap::new(); - for (name, role_def) in roles { - let role: RoleDefinition = serde_json::from_str(&role_def.to_string()).unwrap(); + for (name, role_def) in roles_map { + let role: RoleDefinition = serde_json::from_str(&role_def.to_string())?; let fields: Vec = role.validation_rules.iter().flat_map(|rule| rule.fields.clone()).collect(); for member in role.members { if !all_members.contains_key(&member) { @@ -615,7 +616,7 @@ pub fn create_process_init_transaction( let sp_wallet = local_device.get_wallet(); - let sender: Member = local_device.to_member().unwrap(); + let sender: Member = local_device.to_member().ok_or(ApiError { message: "unpaired device".to_owned() })?; // We first generate the prd with all the keys that we will keep to ourselves let full_prd = Prd::new( @@ -665,7 +666,7 @@ pub fn create_process_init_transaction( let addresses = member.get_addresses(); for sp_address in addresses.into_iter() { let shared_point = sp_utils::sending::calculate_ecdh_shared_secret( - &::try_from(sp_address).unwrap().get_scan_key(), + &::try_from(sp_address)?.get_scan_key(), &partial_secret, ); From b904f4ec815a21198502aa11d97671f340e46a45 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Sat, 21 Sep 2024 18:27:08 +0200 Subject: [PATCH 07/14] Process initial update --- src/api.rs | 1125 +++++++++++++++++++++++++++++++++++----------- src/lib.rs | 35 +- src/user.rs | 2 +- tests/pairing.rs | 233 ++++++---- tests/utils.rs | 40 +- 5 files changed, 1047 insertions(+), 388 deletions(-) diff --git a/src/api.rs b/src/api.rs index 221156d..0043cc8 100644 --- a/src/api.rs +++ b/src/api.rs @@ -5,24 +5,31 @@ use std::io::Write; use std::ops::Index; use std::str::FromStr; use std::string::FromUtf8Error; -use std::sync::{Mutex, OnceLock, PoisonError}; +use std::sync::{Mutex, MutexGuard, OnceLock, PoisonError}; use std::time::{Duration, Instant}; +use std::u32; -use sdk_common::log::{debug, warn}; use rand::{thread_rng, Fill, Rng, RngCore}; +use sdk_common::aes_gcm::aead::generic_array::GenericArray; +use sdk_common::aes_gcm::aes::cipher::ArrayLength; +use sdk_common::aes_gcm::Nonce; +use sdk_common::log::{debug, warn}; +use anyhow::Context; use anyhow::Error as AnyhowError; +use anyhow::Result as AnyhowResult; +use sdk_common::aes_gcm::aead::{Aead, Payload}; use sdk_common::crypto::{ - AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, AnkSharedSecret, KeyInit, Purpose, + AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, AnkSharedSecret, AnkSharedSecretHash, + KeyInit, Purpose, AAD, }; use sdk_common::process::Process; -use sdk_common::signature; use sdk_common::sp_client::bitcoin::blockdata::fee_rate; use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; -use sdk_common::sp_client::bitcoin::hashes::HashEngine; use sdk_common::sp_client::bitcoin::hashes::{sha256, Hash}; +use sdk_common::sp_client::bitcoin::hashes::{FromSliceError, HashEngine}; use sdk_common::sp_client::bitcoin::hex::{ - parse, DisplayHex, FromHex, HexToArrayError, HexToBytesError, + self, parse, DisplayHex, FromHex, HexToArrayError, HexToBytesError, }; use sdk_common::sp_client::bitcoin::key::{Parity, Secp256k1}; use sdk_common::sp_client::bitcoin::network::ParseNetworkError; @@ -43,6 +50,7 @@ use sdk_common::sp_client::silentpayments::{ Error as SpError, }; use sdk_common::uuid::Uuid; +use sdk_common::{signature, MAX_PRD_PAYLOAD_SIZE}; use serde_json::{Error as SerdeJsonError, Map, Value}; use serde::{Deserialize, Serialize}; @@ -50,20 +58,35 @@ use tsify::{JsValueSerdeExt, Tsify}; use wasm_bindgen::convert::{FromWasmAbi, VectorFromWasmAbi}; use wasm_bindgen::prelude::*; +use sdk_common::device::Device; use sdk_common::network::{ - self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage}; -use sdk_common::pcd::{AnkPcdHash, Member, Pcd, RoleDefinition, ValidationRule}; + self, AnkFlag, CachedMessage, CachedMessageStatus, CommitMessage, Envelope, FaucetMessage, + NewTxMessage, +}; +use sdk_common::pcd::{compare_maps, AnkPcdHash, Member, Pcd, RoleDefinition, ValidationRule}; use sdk_common::prd::{AnkPrdHash, Prd, PrdType}; use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address}; use sdk_common::sp_client::spclient::{ derive_keys_from_seed, OutputList, OutputSpendStatus, OwnedOutput, Recipient, SpClient, }; use sdk_common::sp_client::spclient::{SpWallet, SpendKey}; -use sdk_common::device::Device; use crate::user::{lock_local_device, set_new_device, LOCAL_DEVICE}; -use crate::{lock_messages, lock_processes, ProcessState, ProcessStatus, RelevantProcess, CACHEDMESSAGES, CACHEDPROCESSES}; use crate::wallet::{generate_sp_wallet, lock_freezed_utxos}; +use crate::{ + lock_messages, lock_processes, ProcessState, RelevantProcess, CACHEDMESSAGES, CACHEDPROCESSES, +}; + +#[derive(Debug, PartialEq, Tsify, Serialize, Deserialize, Default)] +#[tsify(into_wasm_abi, from_wasm_abi)] +#[allow(non_camel_case_types)] +pub struct ApiReturn { + pub updated_cached_msg: Vec, + pub updated_process: Option<(String, RelevantProcess)>, + pub new_tx_to_send: Option, + pub ciphers_to_send: Vec, + pub commit_to_send: Option, +} pub type ApiResult = Result; @@ -75,99 +98,87 @@ pub struct ApiError { pub message: String, } +impl ApiError { + pub fn new(message: String) -> Self { + ApiError { message } + } +} + impl From for ApiError { fn from(value: AnyhowError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: SpError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) + } +} + +impl From for ApiError { + fn from(value: FromSliceError) -> Self { + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: SerdeJsonError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: HexToBytesError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: HexToArrayError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: sdk_common::sp_client::bitcoin::psbt::PsbtParseError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: sdk_common::sp_client::bitcoin::psbt::ExtractTxError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: sdk_common::sp_client::bitcoin::secp256k1::Error) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: sdk_common::sp_client::bitcoin::consensus::encode::Error) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: FromUtf8Error) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: ParseNetworkError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } impl From for ApiError { fn from(value: ParseOutPointError) -> Self { - ApiError { - message: value.to_string(), - } + ApiError::new(value.to_string()) } } @@ -222,20 +233,28 @@ pub fn create_new_device(birthday: u32, network_str: String) -> ApiResult) -> ApiResult<()> { +pub fn pair_device(commitment_tx: String, mut sp_addresses: Vec) -> ApiResult<()> { let mut local_device = lock_local_device()?; if local_device.is_linked() { - return Err(ApiError { - message: "Already paired".to_owned(), - }); + return Err(ApiError::new("Already paired".to_owned())); } - sp_addresses.push(local_device.get_wallet().get_client().get_receiving_address()); + sp_addresses.push( + local_device + .get_wallet() + .get_client() + .get_receiving_address(), + ); local_device.pair( - Uuid::parse_str(&uuid).unwrap(), - Member::new(sp_addresses.into_iter().map(|a| TryInto::::try_into(a).unwrap()).collect())? + OutPoint::from_str(&commitment_tx)?.txid, + Member::new( + sp_addresses + .into_iter() + .map(|a| TryInto::::try_into(a).unwrap()) + .collect(), + )?, ); Ok(()) @@ -252,6 +271,11 @@ impl outputs_list { } } +#[wasm_bindgen] +pub fn login() -> ApiResult<()> { + unimplemented!(); +} + #[wasm_bindgen] pub fn logout() -> ApiResult<()> { unimplemented!(); @@ -264,6 +288,48 @@ pub fn dump_wallet() -> ApiResult { Ok(serde_json::to_string(device.get_wallet()).unwrap()) } +#[wasm_bindgen] +pub fn reset_process_cache() -> ApiResult<()> { + let mut cached_processes = lock_processes()?; + + *cached_processes = HashMap::new(); + + debug_assert!(cached_processes.is_empty()); + + Ok(()) +} + +#[wasm_bindgen] +pub fn dump_process_cache() -> ApiResult { + let cached_processes = lock_processes()?; + + let serializable_cache = cached_processes + .iter() + .map(|(outpoint, process)| { + ( + outpoint.to_string(), + serde_json::to_value(&process).unwrap(), + ) + }) + .collect::>(); + + let json_string = serde_json::to_string(&serializable_cache) + .map_err(|e| ApiError::new(format!("Failed to serialize process cache: {}", e)))?; + + Ok(json_string) +} + +#[wasm_bindgen] +pub fn set_process_cache(processes: String) -> ApiResult<()> { + let processes: HashMap = serde_json::from_str(&processes)?; + + let mut cached_processes = lock_processes()?; + + *cached_processes = processes; + + Ok(()) +} + #[wasm_bindgen] pub fn reset_message_cache() -> ApiResult<()> { let mut cached_msg = lock_messages()?; @@ -280,9 +346,7 @@ pub fn set_message_cache(msg_cache: Vec) -> ApiResult<()> { let mut cached_msg = lock_messages()?; if !cached_msg.is_empty() { - return Err(ApiError { - message: "Message cache not empty".to_owned(), - }); + return Err(ApiError::new("Message cache not empty".to_owned())); } let new_cache: Result, serde_json::Error> = @@ -319,35 +383,44 @@ pub fn reset_device() -> ApiResult<()> { *device = Device::default(); reset_message_cache()?; + reset_process_cache()?; Ok(()) } +#[wasm_bindgen] +pub fn get_txid(transaction: String) -> ApiResult { + let tx: Transaction = deserialize(&Vec::from_hex(&transaction)?)?; + + Ok(tx.txid().to_string()) +} + fn handle_transaction( updated: HashMap, tx: &Transaction, tweak_data: PublicKey, -) -> anyhow::Result { +) -> AnyhowResult { let device = lock_local_device()?; let sp_wallet = device.get_wallet(); - let op_return = tx.output.iter().find(|o| o.script_pubkey.is_op_return()); - let mut commitment = [0u8; 32]; - if op_return.is_some() { - commitment.copy_from_slice(&op_return.unwrap().script_pubkey.as_bytes()[2..]); - }; - let commitment_str = commitment.to_lower_hex_string(); + let op_return: Vec<&sdk_common::sp_client::bitcoin::TxOut> = tx + .output + .iter() + .filter(|o| o.script_pubkey.is_op_return()) + .collect(); + if op_return.len() != 1 { + return Err(AnyhowError::msg( + "Transaction must have exactly one op_return output", + )); + } + let commitment = + AnkPrdHash::from_slice(&op_return.first().unwrap().script_pubkey.as_bytes()[2..])?; - // If we got updates from a transaction, it means that it creates an output to us, spend an output we owned, or both // Basically a transaction that destroyed utxo is a transaction we sent. let utxo_destroyed: HashMap<&OutPoint, &OwnedOutput> = updated .iter() .filter(|(outpoint, output)| output.spend_status != OutputSpendStatus::Unspent) .collect(); - let utxo_created: HashMap<&OutPoint, &OwnedOutput> = updated - .iter() - .filter(|(outpoint, output)| output.spend_status == OutputSpendStatus::Unspent) - .collect(); let mut messages = lock_messages()?; @@ -372,33 +445,81 @@ fn handle_transaction( return false; } }) { - let (outpoint, output) = utxo_created.into_iter().next().unwrap(); + let prd = Prd::extract_from_message_with_commitment(&plaintext, &commitment)?; - let prd = Prd::extract_from_message(&plaintext, commitment)?; + let proof_key = prd.proof.unwrap().get_key(); + let mut actual_sender = String::default(); + for sp_address in serde_json::from_str::(&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; + } else { + continue; + } + break; + } - message.prd = Some(prd.to_string()); - message.shared_secrets.push(shared_secret.to_byte_array().to_lower_hex_string()); - message.commitment = Some(commitment_str); - message.sender = Some(serde_json::from_str(&prd.sender)?); - message.status = CachedMessageStatus::Opened; + let outpoint = OutPoint::from_str(&prd.root_commitment)?; - return Ok(message.clone()); + let updated_process: RelevantProcess; + if let Some(process) = lock_processes()?.get_mut(&outpoint) { + process.shared_secrets.insert( + actual_sender, + shared_secret.to_byte_array().to_lower_hex_string(), + ); + updated_process = process.clone(); + } else { + let mut shared_secrets = HashMap::new(); + shared_secrets.insert( + actual_sender, + shared_secret.to_byte_array().to_lower_hex_string(), + ); + let new_process = RelevantProcess { + shared_secrets, + ..Default::default() + }; + lock_processes()?.insert(outpoint, new_process.clone()); + updated_process = new_process; + } + + // We don't need the cached message anymore + let id_to_rm = message.id; + *message = CachedMessage { + id: id_to_rm, + ..Default::default() + }; + + return Ok(ApiReturn { + updated_cached_msg: vec![message.clone()], + updated_process: Some((outpoint.to_string(), updated_process)), + ..Default::default() + }); } else { // store it and wait for the message let mut new_msg = CachedMessage::new(); - let (outpoint, output) = utxo_created - .into_iter() - .next() - .expect("utxo_created shouldn't be empty"); - new_msg.commitment = Some(commitment.to_lower_hex_string()); - new_msg.shared_secrets.push(shared_secret.to_byte_array().to_lower_hex_string()); + new_msg.commitment = Some(commitment.as_byte_array().to_lower_hex_string()); + new_msg + .shared_secrets + .push(shared_secret.to_byte_array().to_lower_hex_string()); new_msg.status = CachedMessageStatus::TxWaitingPrd; + messages.push(new_msg.clone()); - return Ok(new_msg.clone()); + + return Ok(ApiReturn { + updated_cached_msg: vec![new_msg.clone()], + ..Default::default() + }); } } else { // We're sender of the transaction, do nothing - return Ok(CachedMessage::new()); + return Ok(ApiReturn { + ..Default::default() + }); } } @@ -408,7 +529,7 @@ fn process_transaction( tx_hex: String, blockheight: u32, tweak_data_hex: String, -) -> anyhow::Result> { +) -> anyhow::Result { let tx = deserialize::(&Vec::from_hex(&tx_hex)?)?; let tweak_data = PublicKey::from_str(&tweak_data_hex)?; @@ -421,113 +542,492 @@ fn process_transaction( } if updated.len() > 0 { - let updated_msg = handle_transaction(updated, &tx, tweak_data)?; - return Ok(Some(updated_msg)); + return handle_transaction(updated, &tx, tweak_data); + } + + Err(anyhow::Error::msg("Transaction is not our")) +} + +#[wasm_bindgen] +pub fn parse_new_tx(new_tx_msg: String, block_height: u32, fee_rate: u32) -> ApiResult { + let new_tx: NewTxMessage = serde_json::from_str(&new_tx_msg)?; + + if let Some(error) = new_tx.error { + return Err(ApiError::new(format!( + "NewTx returned with an error: {}", + error + ))); + } + + if new_tx.tweak_data.is_none() { + return Err(ApiError::new("Missing tweak_data".to_owned())); + } + + Ok(process_transaction( + new_tx.transaction, + block_height, + new_tx.tweak_data.unwrap(), + )?) +} + +fn try_decrypt_with_processes( + cipher: &[u8], + processes: MutexGuard>, +) -> Option<(Vec, SilentPaymentAddress, OutPoint)> { + let nonce = Nonce::from_slice(&cipher[..12]); + + for (outpoint, process) in processes.iter() { + for (address, secret) in &process.shared_secrets { + let aes_key = match AnkSharedSecretHash::from_str(secret) { + Ok(key) => key, + Err(_) => continue, + }; + + let engine = Aes256Gcm::new(aes_key.as_byte_array().into()); + if let Ok(plain) = engine.decrypt( + &nonce, + Payload { + msg: &cipher[12..], + aad: AAD, + }, + ) { + return Some(( + plain, + SilentPaymentAddress::try_from(address.as_str()).unwrap(), + *outpoint, + )); + } + } + } + None +} + +fn confirm_prd(prd: Prd, shared_secret: &str) -> AnyhowResult { + match prd.prd_type { + PrdType::Confirm | PrdType::Response | PrdType::List => { + return Err(AnyhowError::msg("Invalid prd type")); + } + _ => (), + } + + let outpoint = OutPoint::from_str(&prd.root_commitment)?; + + let local_device = lock_local_device()?; + let member = match local_device.to_member() { + Some(member) => member, + None => { + // This might be because we're pairing, let's see if our address is part of sender of the initial prd + let remote_member: Member = serde_json::from_str(&prd.sender)?; + let addresses = remote_member.get_addresses(); + let this_device_address = local_device + .get_wallet() + .get_client() + .get_receiving_address(); + if let Some(_) = addresses.into_iter().find(|a| *a == this_device_address) { + remote_member + } else { + return Err(AnyhowError::msg("Must pair device first")); + } + } + }; + + let payload = Value::from_str(&prd.payload)?; + + let prd_confirm = Prd::new_confirm(outpoint, member, payload.tagged_hash()); + + let prd_msg = prd_confirm.to_network_msg(local_device.get_wallet())?; + + debug!("encrypting with key {}", shared_secret); + Ok(encrypt_with_key(prd_msg, shared_secret.to_owned()).unwrap()) +} + +fn send_data(prd: &Prd, shared_secret: &str) -> AnyhowResult { + let pcd = &prd.payload; + + debug!("encrypting with key: {:#?}", shared_secret); + let cipher = encrypt_with_key(pcd.clone(), shared_secret.to_owned()).unwrap(); + + Ok(ApiReturn { + ciphers_to_send: vec![cipher], + ..Default::default() + }) +} + +fn decrypt_with_cached_messages( + cipher: &[u8], +) -> anyhow::Result, AnkSharedSecretHash)>> { + let mut messages = lock_messages()?; + + let nonce = Nonce::from_slice(&cipher[..12]); + + for message in messages.iter_mut() { + debug!("Attempting decryption with cached message {:#?}", message); + for shared_secret in message.shared_secrets.iter() { + let aes_key = match AnkSharedSecretHash::from_str(shared_secret) { + Ok(key) => key, + Err(_) => { + debug!( + "Invalid shared secret for message{}: {}", + message.id, shared_secret + ); + continue; + } + }; + + let engine = Aes256Gcm::new(aes_key.as_byte_array().into()); + + let plain = match engine.decrypt( + &nonce, + Payload { + msg: &cipher[12..], + aad: AAD, + }, + ) { + Ok(plain) => plain, + Err(_) => continue, + }; + + let commitment = AnkPrdHash::from_str( + message + .commitment + .as_ref() + .ok_or(anyhow::Error::msg("Missing commitment".to_owned()))?, + )?; + // A message matched against a new transaction must be a prd + // We just check the commitment while we're at it + let _ = Prd::extract_from_message_with_commitment(&plain, &commitment)?; + // Update the message status + message.status = CachedMessageStatus::NoStatus; + + return Ok(Some(( + plain, + AnkSharedSecretHash::from_str(message.shared_secrets.first().unwrap())?, + ))); + } } Ok(None) } -#[wasm_bindgen] -pub fn parse_new_tx(new_tx_msg: String, block_height: u32, fee_rate: u32) -> ApiResult> { - let new_tx: NewTxMessage = serde_json::from_str(&new_tx_msg)?; +fn decrypt_with_known_processes(cipher: &[u8]) -> anyhow::Result, OutPoint)>> { + let processes = lock_processes()?; - if let Some(error) = new_tx.error { - return Err(ApiError { - message: format!("NewTx returned with an error: {}", error), - }); + debug!("Known processes: {:#?}", processes); + + let nonce = Nonce::from_slice(&cipher[..12]); + + for (outpoint, process) in processes.iter() { + for (address, secret) in &process.shared_secrets { + debug!("Attempting decryption with key {} for {}", secret, address); + let aes_key = match AnkSharedSecretHash::from_str(secret) { + Ok(key) => key, + Err(_) => { + debug!("Invalid shared secret for process {}: {}", outpoint, secret); + continue; + } + }; + + let engine = Aes256Gcm::new(aes_key.as_byte_array().into()); + + if let Ok(plain) = engine.decrypt( + &nonce, + Payload { + msg: &cipher[12..], + aad: AAD, + }, + ) { + return Ok(Some((plain, *outpoint))); + } + } } - - if new_tx.tweak_data.is_none() { - return Err(ApiError { - message: "Missing tweak_data".to_owned(), - }); - } - - let msg = - process_transaction(new_tx.transaction, block_height, new_tx.tweak_data.unwrap())?; - - Ok(msg) + Ok(None) } -#[wasm_bindgen] -pub fn parse_cipher(cipher_msg: String, fee_rate: u32) -> ApiResult { - // 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(&cipher_msg.trim_matches('\"'))?; - let mut plain = vec![]; - if let Some(message) = messages.iter_mut().find(|m| match m.status { - CachedMessageStatus::TxWaitingPrd | CachedMessageStatus::Opened => { - if let Ok(m) = m.try_decrypt_message(cipher.clone()) { - plain = m; - return true; - } else { return false } - } - _ => return false, - }) { - if message.status == CachedMessageStatus::TxWaitingPrd { - // debug!("Found message {}", String::from_utf8(plain.clone())?); - let mut commitment = [0u8; 32]; - commitment.copy_from_slice(&Vec::from_hex(message.commitment.as_ref().unwrap())?); - let prd = Prd::extract_from_message(&plain, commitment)?; +/// Prd can come with an attached transaction or without +/// It's useful to commit it in a transaction in the case there are multiple recipients (guarantee that everyone gets the same payload) +/// Or if for some reasons we don't want to use the same shared secret again +fn handle_prd( + plain: &[u8], + new_shared_secret: Option, +) -> AnyhowResult { + // We already checked the commitment if any + let prd = Prd::extract_from_message(plain)?; - message.prd = Some(prd.to_string()); - message.sender = Some(serde_json::from_str(&prd.sender)?); - message.status = CachedMessageStatus::Opened; - } else { - // debug!("Found message {}", String::from_utf8(plain.clone())?); - // we're receiving a pcd for a prd we already have - let mut pcd = Value::from_str(&String::from_utf8(plain)?)?; - // check that the hash of the pcd is the same than commited in the prd - let pcd_commitment = AnkPcdHash::from_value(&pcd); - let prd: Prd = serde_json::from_str(message.prd.as_ref().unwrap()).unwrap(); - if pcd_commitment.to_string() != prd.pcd_commitment { - return Err(ApiError { - message: format!("Pcd doesn't match commitment: expected {:?}\ngot {}", prd.pcd_commitment, pcd_commitment), - }); + debug!("found prd: {:#?}", prd); + + let proof_key = prd.proof.unwrap().get_key(); + + let sp_address = serde_json::from_str::(&prd.sender)? + .get_addresses() + .into_iter() + .find_map(|address| { + let parsed_address = SilentPaymentAddress::try_from(address.as_str()).ok()?; + let spend_key = parsed_address.get_spend_key().x_only_public_key().0; + if spend_key == proof_key { + Some(parsed_address) + } else { + None } - message.pcd = Some(pcd.clone()); + }) + .ok_or_else(|| anyhow::Error::msg("No matching address found for the proof key"))?; - // Now we decrypt all we can from the pcd - pcd.decrypt_fields(&prd.keys)?; - - // we take a few mandatory informations - let process = pcd["process"].take(); - let uuid = Uuid::parse_str(&prd.process_uuid).expect("prd can't have an invalid uuid"); - // todo check that the uuid in the process we took from pcd is consistent - - // we complete the process we keep in storage - let mut processes = lock_processes()?; - - match prd.prd_type { - PrdType::Init => { - let relevant_process = RelevantProcess { - process: serde_json::from_value(process)?, - states: vec![ProcessState { - commited_in: OutPoint::null(), // At this point process is not commited yet - encrypted_pcd: message.pcd.clone().unwrap(), - keys: prd.keys.clone(), - validation_token: vec![], - }], - current_status: ProcessStatus::Active(message.shared_secrets.clone()) - }; - processes.insert(uuid, relevant_process); - }, - _ => unimplemented!() - } + let outpoint = OutPoint::from_str(&prd.root_commitment)?; + let mut processes = lock_processes()?; + let relevant_process = match processes.entry(outpoint) { + std::collections::hash_map::Entry::Occupied(entry) => entry.into_mut(), + std::collections::hash_map::Entry::Vacant(entry) => { + debug!("Creating new process for outpoint: {}", outpoint); + let shared_secret = new_shared_secret + .ok_or_else(|| anyhow::Error::msg("Missing shared secret for new process"))?; + let mut shared_secrets = HashMap::new(); + shared_secrets.insert( + sp_address.to_string(), + shared_secret.to_byte_array().to_lower_hex_string(), + ); + entry.insert(RelevantProcess { + shared_secrets, + ..Default::default() + }) } - 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.cipher.push(cipher_msg); - messages.push(new_msg.clone()); - return Ok(new_msg); + }; + + match prd.prd_type { + PrdType::Confirm => { + // It must match a prd we sent previously + // We send the whole data in a pcd + debug!("Received confirm prd {:#?}", prd); + let original_request = relevant_process + .impending_requests + .iter() + .find(|r| { + if r.prd_type != PrdType::Update { + return false; + } + let hash = Value::from_str(&r.payload).unwrap().tagged_hash(); + hash.to_string() == prd.payload + }) + .ok_or(anyhow::Error::msg("Original request not found"))?; + let shared_secret = relevant_process + .shared_secrets + .get(&sp_address.to_string()) + .ok_or(anyhow::Error::msg( + "Missing shared secret for address in original request", + ))?; + + return send_data(original_request, shared_secret); + } + 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.impending_requests.push(prd.clone()); + let shared_secret = relevant_process + .shared_secrets + .get(&sp_address.to_string()) + .ok_or(anyhow::Error::msg( + "Missing shared secret for address in original request", + ))?; + + let cipher = confirm_prd(prd, shared_secret)?; + + return Ok(ApiReturn { + ciphers_to_send: vec![cipher], + updated_process: Some((outpoint.to_string(), relevant_process.clone())), + ..Default::default() + }); + } + _ => unimplemented!(), } } +fn handle_pcd(plain: Vec, root_commitment: OutPoint) -> AnyhowResult { + let pcd = Value::from_str(&String::from_utf8(plain)?)?; + + // debug!("Found pcd: {:#?}", pcd); + let pcd_commitment = pcd.tagged_hash(); + + let mut processes = lock_processes()?; + let relevant_process = processes.get_mut(&root_commitment).unwrap(); + + // We match the pcd with a prd and act accordingly + let prd = relevant_process + .impending_requests + .iter_mut() + .find(|r| Value::from_str(&r.payload).unwrap().tagged_hash() == pcd_commitment) + .ok_or(AnyhowError::msg("Failed to retrieve the matching prd"))?; + + // We update the process and return it + prd.payload = pcd.to_string(); + + debug!("New state of the process: {:#?}", prd); + + return Ok(ApiReturn { + updated_process: Some((root_commitment.to_string(), relevant_process.clone())), + ..Default::default() + }); +} + +fn handle_decrypted_message( + plain: Vec, + shared_secret: Option, + root_commitment: Option, +) -> anyhow::Result { + // Try to handle as PRD first + handle_prd(&plain, shared_secret) + .or_else(|_| { + // If PRD handling fails, try to handle as PCD + handle_pcd( + plain, + root_commitment.ok_or(anyhow::Error::msg( + "root_commitment must be known for a pcd", + ))?, + ) + }) + .map_err(|e| anyhow::Error::msg(format!("Failed to handle decrypted message: {}", e))) +} + +// fn match_with_active_processes(cipher: &[u8]) -> anyhow::Result { +// // 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 { +// // 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::(&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: RelevantProcess; +// 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 = RelevantProcess { +// 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 { + // Check that the cipher is not empty or too long + if cipher_msg.is_empty() || cipher_msg.len() > MAX_PRD_PAYLOAD_SIZE { + return Err(ApiError::new( + "Invalid cipher: empty or too long".to_owned(), + )); + } + + let cipher = Vec::from_hex(cipher_msg.trim_matches('"'))?; + + // Try decrypting with cached messages first + if let Ok(Some((plain, shared_secret))) = decrypt_with_cached_messages(&cipher) { + return handle_decrypted_message(plain, Some(shared_secret), None) + .map_err(|e| ApiError::new(format!("Failed to handle decrypted message: {}", e))); + } + + // If that fails, try decrypting with known processes + if let Ok(Some((plain, root_commitment))) = decrypt_with_known_processes(&cipher) { + return handle_decrypted_message(plain, None, Some(root_commitment)) + .map_err(|e| ApiError::new(format!("Failed to handle decrypted message: {}", e))); + } + + // If both decryption attempts fail, return an error + Err(ApiError::new( + "Failed to decrypt cipher with any known method".to_owned(), + )) +} + #[wasm_bindgen] pub fn get_outputs() -> ApiResult { let device = lock_local_device()?; @@ -543,40 +1043,128 @@ pub fn get_available_amount() -> ApiResult { } #[wasm_bindgen] -pub fn create_process_from_template(json: String) -> ApiResult { - let template_process: Process = serde_json::from_str(&json)?; - let mut new_process = Process::new( - template_process.html, - template_process.style, - template_process.script, - template_process.init_state, - template_process.commited_in - ); +/// This takes some commitment and creates a commit msg so that relay commits it on chain +pub fn create_commit_message( + to_commit: String, + relay_address: String, + init_commitment_outpoint: Option, // if None, we're initializing a new commitment chain + fee_rate: u32, +) -> ApiResult { + let value = Value::from_str(&to_commit)?; + let commitment = value.tagged_hash(); - Ok(new_process) -} + // 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()?; -#[derive(Debug, Tsify, Serialize, Deserialize, Default)] -#[tsify(into_wasm_abi, from_wasm_abi)] -#[allow(non_camel_case_types)] -pub struct createTransactionReturn { - pub txid: String, - pub transaction: String, - pub new_messages: Vec + 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() + }) + } } #[wasm_bindgen] -pub fn create_process_init_transaction( - mut new_process: Process, +/// We assume that the provided tx outpoint exist +pub fn create_update_transaction( + init_commitment: Option, + new_state: String, fee_rate: u32, -) -> ApiResult { - let pcd = new_process.init_state; - let roles = pcd.get("roles").ok_or(ApiError { message: "No roles in init_state".to_owned()})?; - let roles_map = roles.as_object().ok_or(ApiError { message: "roles is not an object".to_owned()})?.clone(); +) -> ApiResult { + let pcd = Value::from_str(&new_state)?; + let pcd_map = pcd + .as_object() + .ok_or(ApiError::new("new_state must be an object".to_owned()))?; + + let mut processes = lock_processes()?; + + let commitment_outpoint: OutPoint; + let relevant_process: &mut RelevantProcess; + if let Some(s) = init_commitment { + // We're updating an existing contract + let outpoint = OutPoint::from_str(&s)?; + + if let Some(p) = processes.get_mut(&outpoint) { + // compare the provided new_state with the process defined template + let previous_state = &p.states.first().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(), + )); + } + relevant_process = p; + commitment_outpoint = outpoint; + } else { + // This is a process we don't know about, so we insert a new entry + processes.insert(outpoint, RelevantProcess::default()); + relevant_process = processes.get_mut(&outpoint).unwrap(); + commitment_outpoint = outpoint; + } + } else { + // This is a creation with an init state, the commitment will come later + // We need a placeholder to keep track of the process before it's commited on chain + // We can take the hash of the init_state as a txid, and set the vout to the max as it is very unlikely to ever have a real commitment that will look like this + let dummy = pcd.tagged_hash(); + + let dummy_outpoint = OutPoint::new(Txid::from_slice(dummy.as_byte_array())?, u32::MAX); + + processes.insert(dummy_outpoint, RelevantProcess::default()); + + relevant_process = processes.get_mut(&dummy_outpoint).unwrap(); + commitment_outpoint = dummy_outpoint; + } + + // We assume that all processes must have a roles key + let roles = pcd + .get("roles") + .ok_or(ApiError::new("No roles in new_state".to_owned()))?; + let roles_map = roles + .as_object() + .ok_or(ApiError::new("roles is not an object".to_owned()))? + .clone(); let mut all_members: HashMap> = HashMap::new(); for (name, role_def) in roles_map { let role: RoleDefinition = serde_json::from_str(&role_def.to_string())?; - let fields: Vec = role.validation_rules.iter().flat_map(|rule| rule.fields.clone()).collect(); + let fields: Vec = role + .validation_rules + .iter() + .flat_map(|rule| rule.fields.clone()) + .collect(); for member in role.members { if !all_members.contains_key(&member) { all_members.insert(member.clone(), HashSet::new()); @@ -587,14 +1175,14 @@ pub fn create_process_init_transaction( let nb_recipients = all_members.len(); if nb_recipients == 0 { - return Err(ApiError { - message: "Can't create a process with 0 member".to_owned(), - }); + return Err(ApiError::new( + "Can't create a process with 0 member".to_owned(), + )); } - let mut recipients: Vec = Vec::with_capacity(nb_recipients*2); // We suppose that will work most of the time - // we actually have multiple "recipients" in a technical sense for each social recipient - // that's necessary because we don't want to miss a notification because we don't have a device atm + let mut recipients: Vec = Vec::with_capacity(nb_recipients * 2); // We suppose that will work most of the time + // we actually have multiple "recipients" in a technical sense for each social recipient + // that's necessary because we don't want to miss a notification because we don't have a device atm for member in all_members.keys() { let addresses = member.get_addresses(); for sp_address in addresses.into_iter() { @@ -608,24 +1196,24 @@ pub fn create_process_init_transaction( let mut fields2keys = Map::new(); let mut fields2cipher = Map::new(); - Value::Object(pcd.clone()).encrypt_fields(&mut fields2keys, &mut fields2cipher); - - new_process.init_state = fields2cipher.clone(); + let encrypted_pcd = pcd.clone(); + encrypted_pcd.encrypt_fields(&mut fields2keys, &mut fields2cipher); let local_device = lock_local_device()?; let sp_wallet = local_device.get_wallet(); - let sender: Member = local_device.to_member().ok_or(ApiError { message: "unpaired device".to_owned() })?; - + let sender: Member = local_device + .to_member() + .ok_or(ApiError::new("unpaired device".to_owned()))?; + // We first generate the prd with all the keys that we will keep to ourselves - let full_prd = Prd::new( - PrdType::Init, - Uuid::from_str(&new_process.uuid).expect("We can trust process to have a valid uuid"), + let full_prd = Prd::new_update( + commitment_outpoint, serde_json::to_string(&sender)?, fields2cipher.clone(), - fields2keys.clone() - )?; + fields2keys.clone(), + ); let prd_commitment = full_prd.create_commitment(); @@ -645,66 +1233,49 @@ pub fn create_process_init_transaction( let partial_secret = sp_wallet .get_client() - .get_partial_secret_from_psbt(&signed_psbt)?; + .get_partial_secret_from_psbt(&signed_psbt)?; let final_tx = signed_psbt.extract_tx()?; - let mut new_messages = vec![]; - let mut shared_secrets = vec![]; // This is a bit ugly, but this way we can update the process status + let mut ciphers = vec![]; + let mut shared_secrets = HashMap::new(); for (member, visible_fields) in all_members { let mut prd = full_prd.clone(); prd.filter_keys(visible_fields); let prd_msg = prd.to_network_msg(sp_wallet)?; - let mut res = CachedMessage::new(); - res.recipient = Some(member.clone()); - res.prd = Some(prd_msg.clone()); - res.sender = Some(sender.clone()); - res.pcd = Some(Value::Object(pcd.clone())); - res.commitment = Some(prd_commitment.to_string()); - res.status = CachedMessageStatus::Opened; let addresses = member.get_addresses(); for sp_address in addresses.into_iter() { let shared_point = sp_utils::sending::calculate_ecdh_shared_secret( - &::try_from(sp_address)?.get_scan_key(), + &::try_from(sp_address.as_str())?.get_scan_key(), &partial_secret, ); - let shared_secret = AnkSharedSecret::new(shared_point).to_byte_array().to_lower_hex_string(); + let shared_secret = AnkSharedSecret::new(shared_point) + .to_byte_array() + .to_lower_hex_string(); - let cipher = encrypt_with_key( - prd_msg.clone(), - shared_secret.clone(), - )?; - res.cipher.push(cipher); - res.shared_secrets.push(shared_secret.clone()); - shared_secrets.push(shared_secret); + let cipher = encrypt_with_key(prd_msg.clone(), shared_secret.clone())?; + ciphers.push(cipher); + shared_secrets.insert(sp_address, shared_secret); } - - new_messages.push(res); } - - lock_messages()?.extend(new_messages.clone()); - - let mut processes = lock_processes()?; - let init_state = ProcessState { + relevant_process.impending_requests.push(full_prd); + relevant_process.shared_secrets.extend(shared_secrets); + relevant_process.states.push(ProcessState { commited_in: OutPoint::null(), encrypted_pcd: Value::Object(fields2cipher), keys: fields2keys, - validation_token: vec![] - }; - - // We are initializing a process, so we shouldn't have it in our cache yet - processes.insert(Uuid::parse_str(&new_process.uuid).unwrap(), RelevantProcess { - process: new_process, - states: vec![init_state], - current_status: ProcessStatus::Active(shared_secrets) + validation_token: vec![], }); - Ok(createTransactionReturn { - txid: final_tx.txid().to_string(), - transaction: serialize(&final_tx).to_lower_hex_string(), - new_messages + debug!("updated_process: {:#?}", relevant_process); + + Ok(ApiReturn { + new_tx_to_send: Some(final_tx), + updated_process: Some((commitment_outpoint.to_string(), relevant_process.clone())), + ciphers_to_send: ciphers, + ..Default::default() }) } @@ -764,9 +1335,7 @@ pub fn encrypt_with_new_key(plaintext: String) -> ApiResult ApiResult { let key_bin = Vec::from_hex(&key)?; if key_bin.len() != 32 { - return Err(ApiError { - message: "key of invalid lenght".to_owned(), - }); + return Err(ApiError::new("key of invalid lenght".to_owned())); } let mut aes_key = [0u8; 32]; aes_key.copy_from_slice(&Vec::from_hex(&key)?); @@ -789,3 +1358,45 @@ pub fn create_faucet_msg() -> ApiResult { Ok(network_msg.to_string()) } + +/// Get active update proposals for a given process outpoint +/// Returns a vector with the latest commited state first and all active proposals +#[wasm_bindgen] +pub fn get_update_proposals(process_outpoint: String) -> ApiResult> { + let outpoint = OutPoint::from_str(&process_outpoint)?; + + let mut processes = lock_processes()?; + + let relevant_process = processes + .get(&outpoint) + .ok_or(ApiError::new("process not found".to_owned()))?; + + let update_proposals: Vec<&Prd> = relevant_process + .impending_requests + .iter() + .filter(|r| r.prd_type == PrdType::Update) + .collect(); + + if update_proposals.is_empty() { + return Err(ApiError::new(format!( + "No active update proposals for process {}", + process_outpoint + ))); + } + + let mut res = vec![]; + + // If we don't have a latest state, it simply means this update is a creation + if let Some(latest_state) = relevant_process.get_latest_state() { + res.push(serde_json::to_string(&latest_state)?); + } + + for proposal in update_proposals { + let pcd = Value::from_str(&proposal.payload)?; + let mut decrypted_pcd = Map::new(); + pcd.decrypt_fields(&proposal.keys, &mut decrypted_pcd)?; + res.push(serde_json::to_string(&decrypted_pcd)?); + } + + Ok(res) +} diff --git a/src/lib.rs b/src/lib.rs index 6e38363..a1d15e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,13 @@ use anyhow::Error; use sdk_common::crypto::AnkSharedSecret; use sdk_common::network::CachedMessage; +use sdk_common::pcd::AnkPcdHash; +use sdk_common::prd::{Prd, ValidationToken}; use sdk_common::process::Process; use sdk_common::sp_client::bitcoin::OutPoint; use sdk_common::uuid::Uuid; -use sdk_common::prd::ValidationToken; use serde::{Deserialize, Serialize}; -use serde_json::{Value, Map}; +use serde_json::{Map, Value}; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::ops::Index; @@ -27,40 +28,34 @@ pub fn lock_messages() -> Result>, Error> .lock_anyhow() } -#[derive(Debug)] -pub enum ProcessStatus { - Sealed, - Active(Vec), // shared_secrets used to communicate on current session -} - -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct ProcessState { pub commited_in: OutPoint, - pub encrypted_pcd: Value, + pub encrypted_pcd: Value, pub keys: Map, // We may not always have all the keys - pub validation_token: Vec // This signs the encrypted pcd + pub validation_token: Vec, // This signs the encrypted pcd } -#[derive(Debug)] +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] pub struct RelevantProcess { - process: Process, states: Vec, - current_status: ProcessStatus, + shared_secrets: HashMap, + impending_requests: Vec, } impl RelevantProcess { - pub fn get_process(&self) -> Process { - self.process.clone() - } - pub fn get_status_at(&self, index: usize) -> Option { self.states.get(index).cloned() } + + pub fn get_latest_state(&self) -> Option { + self.states.last().cloned() + } } -pub static CACHEDPROCESSES: OnceLock>> = OnceLock::new(); +pub static CACHEDPROCESSES: OnceLock>> = OnceLock::new(); -pub fn lock_processes() -> Result>, Error> { +pub fn lock_processes() -> Result>, Error> { CACHEDPROCESSES .get_or_init(|| Mutex::new(HashMap::new())) .lock_anyhow() diff --git a/src/user.rs b/src/user.rs index 360f02f..bab7706 100644 --- a/src/user.rs +++ b/src/user.rs @@ -22,11 +22,11 @@ use std::io::{Cursor, Read, Write}; use std::str::FromStr; use std::sync::{Mutex, MutexGuard, OnceLock}; +use sdk_common::device::Device; use sdk_common::sp_client::bitcoin::secp256k1::constants::SECRET_KEY_SIZE; use sdk_common::sp_client::silentpayments::bitcoin_hashes::sha256; use sdk_common::sp_client::silentpayments::utils::{Network as SpNetwork, SilentPaymentAddress}; use sdk_common::sp_client::spclient::{OutputList, SpWallet, SpendKey}; -use sdk_common::device::Device; use crate::peers::Peer; use crate::wallet::generate_sp_wallet; diff --git a/tests/pairing.rs b/tests/pairing.rs index 252471b..335ff34 100644 --- a/tests/pairing.rs +++ b/tests/pairing.rs @@ -1,17 +1,16 @@ use std::collections::HashMap; +use std::str::FromStr; use sdk_client::api::{ - create_device_from_sp_wallet, create_process_from_template, create_process_init_transaction, get_address, get_outputs, pair_device, reset_device, setup + create_device_from_sp_wallet, create_update_transaction, dump_device, dump_process_cache, + get_address, get_outputs, get_update_proposals, pair_device, parse_cipher, reset_device, + restore_device, set_process_cache, setup, ApiReturn, }; -use sdk_client::lock_processes; -use sdk_common::network::CachedMessage; -use sdk_common::pcd::{Member, Pcd}; -use sdk_common::prd::Prd; +use sdk_common::log::debug; +use sdk_common::pcd::{Member, RoleDefinition}; use sdk_common::sp_client::bitcoin::OutPoint; use sdk_common::sp_client::spclient::OwnedOutput; -use sdk_common::uuid::Uuid; -use sdk_common::log::debug; -use serde_json::{self, json}; +use serde_json::{json, Value}; use tsify::JsValueSerdeExt; use wasm_bindgen_test::*; @@ -38,117 +37,181 @@ fn test_pairing() { let paired_device = helper_get_bob_address(); // Alice creates the new member with Bob address - let new_member = Member::new( - vec![ - device_address.as_str().try_into().unwrap(), - paired_device.as_str().try_into().unwrap(), - ] - ).unwrap(); + let new_member = Member::new(vec![ + device_address.as_str().try_into().unwrap(), + paired_device.as_str().try_into().unwrap(), + ]) + .unwrap(); - // We get the template for the pairing - // We don't really care how we get it, we can even imagine user writing it himself - // It just have to respect the basic Process struct, i.e. have all the fields below and the right type for the value - let pairing_template = json!({ - "uuid": "", + let pairing_init_state = json!({ "html": "", - "script": "", "style": "", - "init_state": { - "roles": { - "owner": { - "members": - [ - new_member - ], - "validation_rules": - [ - { - "quorum": 0.0, - "fields": [ - "roles", - "pairing_tx" - ], - "min_sig_member": 0.0 - } - ] - } - }, - "pairing_tx": "", + "script": "", + "roles": { + "owner": { + "members": + [ + new_member + ], + "validation_rules": + [ + { + "quorum": 0.0, + "fields": [ + "roles", + "pairing_tx" + ], + "min_sig_member": 0.0 + } + ] + } }, - "commited_in": OutPoint::null() + "pairing_tx": OutPoint::null(), }); - let new_process = create_process_from_template(pairing_template.to_string()).unwrap(); + debug!("Alice pairs her device"); + // we can update our local device now, first with an empty txid + pair_device(OutPoint::null().to_string(), vec![helper_get_bob_address()]).unwrap(); - // we can update our local device now - pair_device(new_process.uuid.clone(), vec![helper_get_bob_address()]).unwrap(); + debug!("Alice sends a transaction commiting to an update prd to Bob"); + let alice_pairing_return = + create_update_transaction(None, pairing_init_state.to_string(), 1).unwrap(); - debug!("Alice sends a transaction commiting to an init prd to Bob"); - let alice_pairing_return = create_process_init_transaction(new_process, 1).unwrap(); + // debug!("{:?}", alice_pairing_return); + // todo must take all the necessary validation before commiting + + // debug!("Alice prepares the commit message for the relay"); + // let (outpoint, process) = alice_pairing_return.updated_process.unwrap(); + // let to_commit = process.get_status_at(0).unwrap().encrypted_pcd; + // let init_return = create_commit_message(serde_json::to_string(&to_commit).unwrap(), RELAY_ADDRESS.to_owned(), None, 1).unwrap(); + + // todo send the commit message to the relay + + let pairing_tx = alice_pairing_return.new_tx_to_send.unwrap(); + + // We can update the local device with the actual pairing outpoint + pair_device( + OutPoint::new(pairing_tx.txid(), 0).to_string(), + vec![helper_get_bob_address()], + ) + .unwrap(); + + // This is only for testing, the relay takes care of that in prod let get_outputs_result = get_outputs().unwrap(); let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - let alice_pairing_tweak_data = - helper_get_tweak_data(&alice_pairing_return.transaction, alice_outputs); + let alice_pairing_tweak_data = helper_get_tweak_data(&pairing_tx, alice_outputs); - // Alice parse her own transaction - helper_parse_transaction(&alice_pairing_return.transaction, &alice_pairing_tweak_data).id; + // End of the test only part + + // Alice parses her own transaction + helper_parse_transaction(&pairing_tx, &alice_pairing_tweak_data); // Notify user that we're waiting for confirmation from the other device + let alice_device = dump_device().unwrap(); + let alice_processes = dump_process_cache().unwrap(); + debug!("Alice processes: {:#?}", alice_processes); + // ======================= Bob reset_device().unwrap(); create_device_from_sp_wallet(BOB_LOGIN_WALLET.to_owned()).unwrap(); // Bob receives Alice pairing transaction debug!("Bob parses Alice pairing transaction"); - helper_parse_transaction(&alice_pairing_return.transaction, &alice_pairing_tweak_data); + helper_parse_transaction(&pairing_tx, &alice_pairing_tweak_data); debug!("Bob receives the prd"); - let mut bob_retrieved_prd = CachedMessage::default(); - for message in alice_pairing_return.new_messages.iter() { - for cipher in message.cipher.iter() { - match helper_parse_cipher(cipher.clone()) { - Ok(res) => bob_retrieved_prd = res, - Err(_) => continue + let mut bob_retrieved_prd: ApiReturn = ApiReturn::default(); + for cipher in alice_pairing_return.ciphers_to_send.iter() { + // debug!("Parsing cipher: {:#?}", cipher); + match parse_cipher(cipher.clone()) { + Ok(res) => bob_retrieved_prd = res, + Err(e) => { + debug!("Error parsing cipher: {:#?}", e); + continue; } } } - if bob_retrieved_prd == CachedMessage::default() { - panic!("Bob failed to retrieve Alice message"); - } + assert!(bob_retrieved_prd != ApiReturn::default()); - debug!("Bob receives the pcd"); - let mut bob_retrieved_pcd = CachedMessage::default(); - for message in alice_pairing_return.new_messages { - for cipher in message.cipher { - match helper_parse_cipher(cipher) { - Ok(res) => bob_retrieved_pcd = res, - Err(_) => continue - } - } - } + debug!("Bob retrieved prd: {:#?}", bob_retrieved_prd); - if bob_retrieved_pcd == CachedMessage::default() { - panic!("Bob failed to retrieve Alice message"); - } + debug!("Bob sends a Confirm Prd to Alice"); + + let bob_device = dump_device().unwrap(); + let bob_processes = dump_process_cache().unwrap(); + + // ======================= Alice + reset_device().unwrap(); + restore_device(alice_device).unwrap(); + set_process_cache(alice_processes).unwrap(); + + debug!("Alice receives the Confirm Prd"); + let alice_parsed_prd = parse_cipher(bob_retrieved_prd.ciphers_to_send[0].clone()).unwrap(); + + debug!("Alice parsed Bob's Confirm Prd: {:#?}", alice_parsed_prd); + + // ======================= Bob + reset_device().unwrap(); + restore_device(bob_device).unwrap(); + set_process_cache(bob_processes).unwrap(); + + let bob_parsed_pcd_return = parse_cipher(alice_parsed_prd.ciphers_to_send[0].clone()).unwrap(); + + debug!("bob_parsed_pcd: {:#?}", bob_parsed_pcd_return); // At this point, user must validate the pairing proposal received from Alice + // We decrypt the content of the pcd so that we can display to user what matters + let alice_proposal = + get_update_proposals(bob_parsed_pcd_return.updated_process.unwrap().0).unwrap(); - debug!("Bob pairs device with Alice"); - let process = lock_processes().unwrap(); - let prd: Prd = serde_json::from_str(&bob_retrieved_prd.prd.unwrap()).unwrap(); - let relevant_process = process.get(&Uuid::parse_str(&prd.process_uuid).unwrap()).unwrap(); - // decrypt the pcd and update bob device - if let Some(initial_state) = relevant_process.get_status_at(0) { - let keys = initial_state.keys; - let mut pcd = initial_state.encrypted_pcd; - pcd.decrypt_fields(&keys).unwrap(); - pair_device(relevant_process.get_process().uuid, vec![device_address]).unwrap(); - } + debug!("Alice proposal: {:#?}", alice_proposal); + + // get the pairing tx from the proposal + let proposal = Value::from_str(&alice_proposal.get(0).unwrap()).unwrap(); + let pairing_tx = proposal.get("pairing_tx").unwrap().as_str().unwrap(); + let roles: RoleDefinition = + serde_json::from_str(proposal.get("roles").unwrap().as_str().unwrap()).unwrap(); + + // we check that the proposal contains only one member + assert!(roles.members.len() == 1); + + // we get all the addresses of the members of the proposal + let proposal_members = roles + .members + .iter() + .flat_map(|member| member.get_addresses()) + .collect::>(); + + // we can automatically check that a pairing member contains local device address + the one that sent the proposal + assert!(proposal_members.contains(&device_address)); + assert!(proposal_members.contains(&paired_device)); + assert!(proposal_members.len() == 2); // no free riders + + // we can now show all the addresses + pairing tx to the user on device to prompt confirmation + + pair_device(pairing_tx.to_owned(), proposal_members).unwrap(); + + // Bob signs the proposal and send a prd response to Alice + + // debug!("Bob pairs device with Alice"); + // let process = lock_processes().unwrap(); + // let prd: Prd = serde_json::from_str(&bob_retrieved_prd.prd.unwrap()).unwrap(); + // let relevant_process = process.get(&Uuid::parse_str(&prd.process_uuid).unwrap()).unwrap(); + // // decrypt the pcd and update bob device + // let pairing_tx: Txid; + // if let Some(initial_state) = relevant_process.get_status_at(0) { + // let keys = initial_state.keys; + // let mut pcd = initial_state.encrypted_pcd; + // pcd.decrypt_fields(&keys).unwrap(); + // debug!("decrypted pcd: {:?}", pcd); + // pairing_tx = Txid::from_str(pcd.get("pairing_tx").unwrap().as_str().unwrap()).unwrap(); + // pair_device(relevant_process.get_process().uuid, vec![device_address]).unwrap(); + // } // To make the pairing effective, alice and bob must now spend their respective output into a new transaction // login(); diff --git a/tests/utils.rs b/tests/utils.rs index 262c209..63e5ce5 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -1,18 +1,15 @@ use std::collections::HashMap; -use sdk_client::api::{parse_cipher, parse_new_tx, reset_device, ApiResult}; -use sdk_common::network::{ - CachedMessage, NewTxMessage, -}; -use sdk_common::sp_client::bitcoin::consensus::deserialize; -use sdk_common::sp_client::bitcoin::hex::FromHex; +use sdk_client::api::{parse_cipher, parse_new_tx, ApiResult, ApiReturn}; +use sdk_common::network::NewTxMessage; +use sdk_common::sp_client::bitcoin::consensus::serialize; +use sdk_common::sp_client::bitcoin::hex::DisplayHex; use sdk_common::sp_client::bitcoin::secp256k1::PublicKey; use sdk_common::sp_client::bitcoin::{OutPoint, ScriptBuf, Transaction}; use sdk_common::sp_client::silentpayments::utils::receiving::{ calculate_tweak_data, get_pubkey_from_input, }; use sdk_common::sp_client::spclient::{OwnedOutput, SpWallet}; -use sdk_common::log::debug; use serde_json; // We're using alice and bob for clarity, but it's important to remember that for pairing and login Alice and Bob are the same person @@ -37,6 +34,7 @@ pub const ALICE_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"d pub const BOB_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:1\":{\"blockheight\":0,\"tweak\":\"281ea54f74e5f6582a7462bdd9397b9a786f97455e858e7901a6a4fa95f39192\",\"amount\":654,\"script\":\"5120aa4395e2be9cbce580e94f4308d64422da251b7df12fb8c571675d40cc50cf00\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\":{\"blockheight\":0,\"tweak\":\"21fc32bded971dd15387671436232f17d932e18758f69b476219e2d6e688767f\",\"amount\":1200,\"script\":\"5120230d06322d10a5838634df3c55eef9959a1c0c144108e0416b9687eaf22e6baa\",\"label\":null,\"spend_status\":{\"Spent\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; pub const ALICE_FINAL_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\":{\"blockheight\":0,\"tweak\":\"de507c854cee16d2e157fbf6c6dbfd2e721b861efc7f657bb724790fc7829665\",\"amount\":349,\"script\":\"5120028143243ed5d4554e60d96ee61fdf6f6e359a9083311c210645c0a7fef51248\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; +pub const RELAY_ADDRESS: &str = "sprt1qqfmqt0ngq99y8t4ke6uhtm2a2vc2zxvhj7hjrqu599kn30d4cs9rwqn6n079mdr4dfqg72yrtvuxf43yswscw86nvvl09mc5ljx65vfh75fkza35"; pub const DEFAULT_NYM: &str = "AliceBob"; pub fn helper_get_alice_address() -> String { @@ -49,17 +47,19 @@ pub fn helper_get_bob_address() -> String { wallet.get_client().get_receiving_address() } -pub fn helper_get_tweak_data(transaction: &str, outpoints: HashMap) -> String { - let tx = deserialize::(&Vec::from_hex(transaction).unwrap()).unwrap(); +pub fn helper_get_tweak_data( + tx: &Transaction, + outpoints: HashMap, +) -> String { let mut outpoint_data = vec![]; let mut witnesses = vec![]; let mut spks = vec![]; - for prevout in tx.input { + for prevout in tx.input.iter() { outpoint_data.push(( prevout.previous_output.txid.to_string(), prevout.previous_output.vout, )); - witnesses.push(prevout.witness); + witnesses.push(prevout.witness.clone()); if let Some(output) = outpoints.get(&prevout.previous_output) { spks.push(ScriptBuf::from_hex(&output.script).unwrap()); } @@ -75,26 +75,16 @@ pub fn helper_get_tweak_data(transaction: &str, outpoints: HashMap CachedMessage { +pub fn helper_parse_transaction(transaction: &Transaction, tweak_data: &str) -> ApiReturn { let new_tx_msg = serde_json::to_string(&NewTxMessage::new( - transaction.to_owned(), + serialize(transaction).to_lower_hex_string(), Some(tweak_data.to_owned()), )) .unwrap(); - debug!("new_tx_msg: {:?}", new_tx_msg); + // debug!("new_tx_msg: {:?}", new_tx_msg); let result = parse_new_tx(new_tx_msg, 0, 1); match result { - Ok(m) => { - if m.is_some() { - m.unwrap() - } else { - panic!("Failed to find our tx"); - } - }, + Ok(m) => m, Err(e) => panic!("Unexpected error: {}", e.message), } } - -pub fn helper_parse_cipher(cipher_msg: String) -> ApiResult { - parse_cipher(cipher_msg, 1) -} From 56558703c3c214407386786922f47fa822565b58 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Mon, 23 Sep 2024 12:33:32 +0200 Subject: [PATCH 08/14] Add response logic --- src/api.rs | 92 +++++++++++++++++++++++++---- src/lib.rs | 10 +++- tests/pairing.rs | 151 +++++++++++++++++++++++++++++++---------------- 3 files changed, 189 insertions(+), 64 deletions(-) diff --git a/src/api.rs b/src/api.rs index 0043cc8..0f246d6 100644 --- a/src/api.rs +++ b/src/api.rs @@ -24,9 +24,10 @@ use sdk_common::crypto::{ KeyInit, Purpose, AAD, }; use sdk_common::process::Process; +use sdk_common::signature::{AnkHash, AnkValidationNoHash, AnkValidationYesHash, Proof}; use sdk_common::sp_client::bitcoin::blockdata::fee_rate; use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; -use sdk_common::sp_client::bitcoin::hashes::{sha256, Hash}; +use sdk_common::sp_client::bitcoin::hashes::{sha256, sha256t, Hash}; use sdk_common::sp_client::bitcoin::hashes::{FromSliceError, HashEngine}; use sdk_common::sp_client::bitcoin::hex::{ self, parse, DisplayHex, FromHex, HexToArrayError, HexToBytesError, @@ -63,7 +64,9 @@ use sdk_common::network::{ self, AnkFlag, CachedMessage, CachedMessageStatus, CommitMessage, Envelope, FaucetMessage, NewTxMessage, }; -use sdk_common::pcd::{compare_maps, AnkPcdHash, Member, Pcd, RoleDefinition, ValidationRule}; +use sdk_common::pcd::{ + compare_maps, AnkPcdHash, AnkPcdTag, Member, Pcd, RoleDefinition, ValidationRule, +}; use sdk_common::prd::{AnkPrdHash, Prd, PrdType}; use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address}; use sdk_common::sp_client::spclient::{ @@ -602,6 +605,56 @@ fn try_decrypt_with_processes( None } +#[wasm_bindgen] +pub fn response_prd( + root_commitment: String, + prd: String, // The Prd we respond to + approval: bool, +) -> ApiResult { + let local_device = lock_local_device()?; + let member = local_device + .to_member() + .ok_or(ApiError::new("Unpaired device".to_owned()))?; + + let prd_to_respond = serde_json::from_str::(&prd)?; + + // Probably we should answer differently depending on the type of prd + let message_hash = match prd_to_respond.prd_type { + PrdType::Update => { + let pcd_hash: AnkPcdHash = + AnkPcdHash::from_value(&Value::from_str(&prd_to_respond.payload)?); + + let message_hash = if approval { + AnkHash::ValidationYes(AnkValidationYesHash::from_commitment(pcd_hash)) + } else { + AnkHash::ValidationNo(AnkValidationNoHash::from_commitment(pcd_hash)) + }; + + let proof = Proof::new( + message_hash, + local_device + .get_wallet() + .get_client() + .get_spend_key() + .try_into()?, + ); + + let prd = Prd::new_response( + OutPoint::from_str(&root_commitment)?, + serde_json::to_string(&member)?, + proof, + pcd_hash, + ); + + return Ok(ApiReturn { + ciphers_to_send: vec![prd.to_network_msg(local_device.get_wallet())?.to_string()], + ..Default::default() + }); + } + _ => unimplemented!(), + }; +} + fn confirm_prd(prd: Prd, shared_secret: &str) -> AnyhowResult { match prd.prd_type { PrdType::Confirm | PrdType::Response | PrdType::List => { @@ -631,20 +684,18 @@ fn confirm_prd(prd: Prd, shared_secret: &str) -> AnyhowResult { } }; - let payload = Value::from_str(&prd.payload)?; + let pcd_commitment = AnkPcdHash::from_str(&prd.payload)?; - let prd_confirm = Prd::new_confirm(outpoint, member, payload.tagged_hash()); + let prd_confirm = Prd::new_confirm(outpoint, member, pcd_commitment); let prd_msg = prd_confirm.to_network_msg(local_device.get_wallet())?; - debug!("encrypting with key {}", shared_secret); Ok(encrypt_with_key(prd_msg, shared_secret.to_owned()).unwrap()) } fn send_data(prd: &Prd, shared_secret: &str) -> AnyhowResult { let pcd = &prd.payload; - debug!("encrypting with key: {:#?}", shared_secret); let cipher = encrypt_with_key(pcd.clone(), shared_secret.to_owned()).unwrap(); Ok(ApiReturn { @@ -661,7 +712,6 @@ fn decrypt_with_cached_messages( let nonce = Nonce::from_slice(&cipher[..12]); for message in messages.iter_mut() { - debug!("Attempting decryption with cached message {:#?}", message); for shared_secret in message.shared_secrets.iter() { let aes_key = match AnkSharedSecretHash::from_str(shared_secret) { Ok(key) => key, @@ -837,6 +887,24 @@ fn handle_prd( ..Default::default() }); } + PrdType::Response => { + // We must know of a prd update that the response answers to + let original_request = relevant_process + .impending_requests + .iter() + .find(|r| { + if r.prd_type != PrdType::Update { + return false; + } + let hash = Value::from_str(&r.payload).unwrap().tagged_hash(); + hash.to_string() == prd.payload + }) + .ok_or(anyhow::Error::msg("Original request not found"))?; + + return Ok(ApiReturn { + ..Default::default() + }); + } _ => unimplemented!(), } } @@ -844,7 +912,6 @@ fn handle_prd( fn handle_pcd(plain: Vec, root_commitment: OutPoint) -> AnyhowResult { let pcd = Value::from_str(&String::from_utf8(plain)?)?; - // debug!("Found pcd: {:#?}", pcd); let pcd_commitment = pcd.tagged_hash(); let mut processes = lock_processes()?; @@ -854,7 +921,7 @@ fn handle_pcd(plain: Vec, root_commitment: OutPoint) -> AnyhowResult Result>, Error> .lock_anyhow() } +// TODO move to sdk-common #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct ProcessState { pub commited_in: OutPoint, pub encrypted_pcd: Value, pub keys: Map, // We may not always have all the keys - pub validation_token: Vec, // This signs the encrypted pcd + pub validation_token: Vec, // This signs the encrypted pcd } #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] @@ -51,6 +53,10 @@ impl RelevantProcess { pub fn get_latest_state(&self) -> Option { self.states.last().cloned() } + + pub fn get_impending_requests(&self) -> Vec { + self.impending_requests.clone() + } } pub static CACHEDPROCESSES: OnceLock>> = OnceLock::new(); diff --git a/tests/pairing.rs b/tests/pairing.rs index 335ff34..affc254 100644 --- a/tests/pairing.rs +++ b/tests/pairing.rs @@ -4,10 +4,10 @@ use std::str::FromStr; use sdk_client::api::{ create_device_from_sp_wallet, create_update_transaction, dump_device, dump_process_cache, get_address, get_outputs, get_update_proposals, pair_device, parse_cipher, reset_device, - restore_device, set_process_cache, setup, ApiReturn, + response_prd, restore_device, set_process_cache, setup, ApiReturn, }; use sdk_common::log::debug; -use sdk_common::pcd::{Member, RoleDefinition}; +use sdk_common::pcd::{Member, Pcd, RoleDefinition}; use sdk_common::sp_client::bitcoin::OutPoint; use sdk_common::sp_client::spclient::OwnedOutput; use serde_json::{json, Value}; @@ -31,15 +31,15 @@ fn test_pairing() { create_device_from_sp_wallet(ALICE_LOGIN_WALLET.to_owned()).unwrap(); // we get our own address - let device_address = get_address().unwrap(); + let alice_address = get_address().unwrap(); // we scan the qr code or get the address by any other means - let paired_device = helper_get_bob_address(); + let bob_address = helper_get_bob_address(); // Alice creates the new member with Bob address let new_member = Member::new(vec![ - device_address.as_str().try_into().unwrap(), - paired_device.as_str().try_into().unwrap(), + alice_address.as_str().try_into().unwrap(), + bob_address.as_str().try_into().unwrap(), ]) .unwrap(); @@ -47,6 +47,7 @@ fn test_pairing() { "html": "", "style": "", "script": "", + "description": "AliceBob", "roles": { "owner": { "members": @@ -77,26 +78,19 @@ fn test_pairing() { let alice_pairing_return = create_update_transaction(None, pairing_init_state.to_string(), 1).unwrap(); - // debug!("{:?}", alice_pairing_return); - - // todo must take all the necessary validation before commiting - - // debug!("Alice prepares the commit message for the relay"); - // let (outpoint, process) = alice_pairing_return.updated_process.unwrap(); - // let to_commit = process.get_status_at(0).unwrap().encrypted_pcd; - // let init_return = create_commit_message(serde_json::to_string(&to_commit).unwrap(), RELAY_ADDRESS.to_owned(), None, 1).unwrap(); - - // todo send the commit message to the relay + let (root_outpoint, alice_init_process) = alice_pairing_return.updated_process.unwrap(); + let alice_pcd_commitment = Value::from_str( + &alice_init_process + .get_impending_requests() + .get(0) + .unwrap() + .payload, + ) + .unwrap() + .tagged_hash(); let pairing_tx = alice_pairing_return.new_tx_to_send.unwrap(); - // We can update the local device with the actual pairing outpoint - pair_device( - OutPoint::new(pairing_tx.txid(), 0).to_string(), - vec![helper_get_bob_address()], - ) - .unwrap(); - // This is only for testing, the relay takes care of that in prod let get_outputs_result = get_outputs().unwrap(); @@ -110,10 +104,35 @@ fn test_pairing() { helper_parse_transaction(&pairing_tx, &alice_pairing_tweak_data); // Notify user that we're waiting for confirmation from the other device + // We can update the local device with the actual pairing outpoint + pair_device( + OutPoint::new(pairing_tx.txid(), 0).to_string(), + vec![helper_get_bob_address()], + ) + .unwrap(); + // TODO unpair device + + // We can produce the prd response now even if we can't use it yet + // TODO pass the process as argument + let alice_prd_response = response_prd( + root_outpoint, + alice_init_process + .get_impending_requests() + .get(0) + .unwrap() + .to_string(), + true, + ) + .unwrap() + .ciphers_to_send + .get(0) + .unwrap() + .clone(); + + // this is only for testing, as we're playing both parts let alice_device = dump_device().unwrap(); let alice_processes = dump_process_cache().unwrap(); - debug!("Alice processes: {:#?}", alice_processes); // ======================= Bob reset_device().unwrap(); @@ -136,12 +155,23 @@ fn test_pairing() { } } - assert!(bob_retrieved_prd != ApiReturn::default()); + assert!(bob_retrieved_prd.ciphers_to_send.len() == 1); + assert!(bob_retrieved_prd.updated_process.is_some()); debug!("Bob retrieved prd: {:#?}", bob_retrieved_prd); + let (root_commitment, relevant_process) = bob_retrieved_prd.updated_process.unwrap(); + let pcd_commitment = relevant_process + .get_impending_requests() + .get(0) + .unwrap() + .payload + .clone(); + let prd_confirm_cipher = bob_retrieved_prd.ciphers_to_send.iter().next().unwrap(); + debug!("Bob sends a Confirm Prd to Alice"); + // this is only for testing, as we're playing both parts let bob_device = dump_device().unwrap(); let bob_processes = dump_process_cache().unwrap(); @@ -151,7 +181,7 @@ fn test_pairing() { set_process_cache(alice_processes).unwrap(); debug!("Alice receives the Confirm Prd"); - let alice_parsed_prd = parse_cipher(bob_retrieved_prd.ciphers_to_send[0].clone()).unwrap(); + let alice_parsed_prd = parse_cipher(prd_confirm_cipher.clone()).unwrap(); debug!("Alice parsed Bob's Confirm Prd: {:#?}", alice_parsed_prd); @@ -160,6 +190,7 @@ fn test_pairing() { restore_device(bob_device).unwrap(); set_process_cache(bob_processes).unwrap(); + debug!("Bob parses Alice's pcd"); let bob_parsed_pcd_return = parse_cipher(alice_parsed_prd.ciphers_to_send[0].clone()).unwrap(); debug!("bob_parsed_pcd: {:#?}", bob_parsed_pcd_return); @@ -173,47 +204,65 @@ fn test_pairing() { // get the pairing tx from the proposal let proposal = Value::from_str(&alice_proposal.get(0).unwrap()).unwrap(); - let pairing_tx = proposal.get("pairing_tx").unwrap().as_str().unwrap(); - let roles: RoleDefinition = - serde_json::from_str(proposal.get("roles").unwrap().as_str().unwrap()).unwrap(); + debug!("proposal: {:#?}", proposal); + let pairing_tx = proposal + .get("pairing_tx") + .unwrap() + .as_str() + .unwrap() + .trim_matches('"'); + + let roles = proposal + .get("roles") + .and_then(|v| Value::from_str(v.as_str().unwrap()).ok()) + .unwrap() + .as_object() + .unwrap() + .iter() + .map(|(role_name, role_value)| { + let role_def: RoleDefinition = serde_json::from_value(role_value.clone())?; + Ok((role_name.clone(), role_def)) + }) + .collect::, anyhow::Error>>(); + + let roles = roles.unwrap(); // we check that the proposal contains only one member - assert!(roles.members.len() == 1); + assert!(roles.len() == 1); + assert!(roles["owner"].members.len() == 1); // we get all the addresses of the members of the proposal let proposal_members = roles - .members .iter() - .flat_map(|member| member.get_addresses()) + .flat_map(|(_, members)| members.members.iter().flat_map(|m| m.get_addresses())) .collect::>(); // we can automatically check that a pairing member contains local device address + the one that sent the proposal - assert!(proposal_members.contains(&device_address)); - assert!(proposal_members.contains(&paired_device)); + assert!(proposal_members.contains(&alice_address)); + assert!(proposal_members.contains(&bob_address)); assert!(proposal_members.len() == 2); // no free riders + // We remove the local address, but maybe that's the responsibility of the Member type + let proposal_members = proposal_members + .into_iter() + .filter(|m| m != &bob_address) + .collect::>(); + + debug!("proposal_members: {:?}", proposal_members); + // we can now show all the addresses + pairing tx to the user on device to prompt confirmation + debug!("Bob pairs device with Alice"); pair_device(pairing_tx.to_owned(), proposal_members).unwrap(); - // Bob signs the proposal and send a prd response to Alice + // Bob signs the proposal and sends a prd response too + let bob_prd_response = response_prd(root_commitment, pcd_commitment, true) + .unwrap() + .ciphers_to_send + .get(0) + .unwrap(); - // debug!("Bob pairs device with Alice"); - // let process = lock_processes().unwrap(); - // let prd: Prd = serde_json::from_str(&bob_retrieved_prd.prd.unwrap()).unwrap(); - // let relevant_process = process.get(&Uuid::parse_str(&prd.process_uuid).unwrap()).unwrap(); - // // decrypt the pcd and update bob device - // let pairing_tx: Txid; - // if let Some(initial_state) = relevant_process.get_status_at(0) { - // let keys = initial_state.keys; - // let mut pcd = initial_state.encrypted_pcd; - // pcd.decrypt_fields(&keys).unwrap(); - // debug!("decrypted pcd: {:?}", pcd); - // pairing_tx = Txid::from_str(pcd.get("pairing_tx").unwrap().as_str().unwrap()).unwrap(); - // pair_device(relevant_process.get_process().uuid, vec![device_address]).unwrap(); - // } - - // To make the pairing effective, alice and bob must now spend their respective output into a new transaction + // To make the pairing effective, alice and bob must now creates a new transaction where they both control one output // login(); // Once we know this tx id, we can commit to the relay From 1871dc9a5dd65f58d565239f52d2c5fcd8496ea9 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Mon, 23 Sep 2024 12:44:20 +0200 Subject: [PATCH 09/14] Import MutexExt trait from common --- src/lib.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 31490e6..a892a68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ use sdk_common::process::Process; use sdk_common::signature::Proof; use sdk_common::sp_client::bitcoin::OutPoint; use sdk_common::uuid::Uuid; +use sdk_common::MutexExt; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use std::collections::{HashMap, HashSet}; @@ -66,14 +67,3 @@ pub fn lock_processes() -> Result { - fn lock_anyhow(&self) -> Result, Error>; -} - -impl MutexExt for Mutex { - fn lock_anyhow(&self) -> Result, Error> { - self.lock() - .map_err(|e| Error::msg(format!("Failed to lock: {}", e))) - } -} From 836f6cf9009a3ef989ba54899fbd5257a782292d Mon Sep 17 00:00:00 2001 From: Sosthene Date: Wed, 25 Sep 2024 12:51:23 +0200 Subject: [PATCH 10/14] Working pairing --- src/api.rs | 198 +++++++++++++++-------------------------------- src/lib.rs | 51 ------------ src/user.rs | 5 +- tests/pairing.rs | 16 +++- tests/utils.rs | 18 +---- 5 files changed, 76 insertions(+), 212 deletions(-) diff --git a/src/api.rs b/src/api.rs index 0f246d6..f9327f0 100644 --- a/src/api.rs +++ b/src/api.rs @@ -20,10 +20,9 @@ use anyhow::Error as AnyhowError; use anyhow::Result as AnyhowResult; use sdk_common::aes_gcm::aead::{Aead, Payload}; use sdk_common::crypto::{ - AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, AnkSharedSecret, AnkSharedSecretHash, - KeyInit, Purpose, AAD, + encrypt_with_key, AeadCore, Aes256Gcm, AnkSharedSecretHash, KeyInit, AAD }; -use sdk_common::process::Process; +use sdk_common::process::{lock_processes, Process, ProcessState}; use sdk_common::signature::{AnkHash, AnkValidationNoHash, AnkValidationYesHash, Proof}; use sdk_common::sp_client::bitcoin::blockdata::fee_rate; use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; @@ -50,7 +49,6 @@ use sdk_common::sp_client::silentpayments::{ utils::{Network as SpNetwork, SilentPaymentAddress}, Error as SpError, }; -use sdk_common::uuid::Uuid; use sdk_common::{signature, MAX_PRD_PAYLOAD_SIZE}; use serde_json::{Error as SerdeJsonError, Map, Value}; @@ -77,7 +75,7 @@ use sdk_common::sp_client::spclient::{SpWallet, SpendKey}; use crate::user::{lock_local_device, set_new_device, LOCAL_DEVICE}; use crate::wallet::{generate_sp_wallet, lock_freezed_utxos}; use crate::{ - lock_messages, lock_processes, ProcessState, RelevantProcess, CACHEDMESSAGES, CACHEDPROCESSES, + lock_messages, CACHEDMESSAGES, }; #[derive(Debug, PartialEq, Tsify, Serialize, Deserialize, Default)] @@ -85,7 +83,7 @@ use crate::{ #[allow(non_camel_case_types)] pub struct ApiReturn { pub updated_cached_msg: Vec, - pub updated_process: Option<(String, RelevantProcess)>, + pub updated_process: Option<(String, Process)>, pub new_tx_to_send: Option, pub ciphers_to_send: Vec, pub commit_to_send: Option, @@ -263,6 +261,15 @@ pub fn pair_device(commitment_tx: String, mut sp_addresses: Vec) -> ApiR Ok(()) } +#[wasm_bindgen] +pub fn unpair_device() -> ApiResult<()> { + let mut local_device = lock_local_device()?; + + local_device.unpair(); + + Ok(()) +} + #[derive(Debug, Tsify, Serialize, Deserialize)] #[tsify(from_wasm_abi, into_wasm_abi)] #[allow(non_camel_case_types)] @@ -324,7 +331,7 @@ pub fn dump_process_cache() -> ApiResult { #[wasm_bindgen] pub fn set_process_cache(processes: String) -> ApiResult<()> { - let processes: HashMap = serde_json::from_str(&processes)?; + let processes: HashMap = serde_json::from_str(&processes)?; let mut cached_processes = lock_processes()?; @@ -433,7 +440,7 @@ fn handle_transaction( &tweak_data, &sp_wallet.get_client().get_scan_key(), ); - let shared_secret = AnkSharedSecret::new(shared_point); + let shared_secret = AnkSharedSecretHash::from_shared_point(shared_point); let mut plaintext: Vec = vec![]; if let Some(message) = messages.iter_mut().find(|m| { @@ -469,23 +476,20 @@ fn handle_transaction( let outpoint = OutPoint::from_str(&prd.root_commitment)?; - let updated_process: RelevantProcess; + let updated_process: Process; if let Some(process) = lock_processes()?.get_mut(&outpoint) { - process.shared_secrets.insert( - actual_sender, - shared_secret.to_byte_array().to_lower_hex_string(), + process.insert_shared_secret( + SilentPaymentAddress::try_from(actual_sender.as_str()).unwrap(), + shared_secret, ); updated_process = process.clone(); } else { let mut shared_secrets = HashMap::new(); shared_secrets.insert( - actual_sender, - shared_secret.to_byte_array().to_lower_hex_string(), + SilentPaymentAddress::try_from(actual_sender.as_str()).unwrap(), + shared_secret, ); - let new_process = RelevantProcess { - shared_secrets, - ..Default::default() - }; + let new_process = Process::new(vec![], shared_secrets, vec![]); lock_processes()?.insert(outpoint, new_process.clone()); updated_process = new_process; } @@ -575,18 +579,13 @@ pub fn parse_new_tx(new_tx_msg: String, block_height: u32, fee_rate: u32) -> Api fn try_decrypt_with_processes( cipher: &[u8], - processes: MutexGuard>, + processes: MutexGuard>, ) -> Option<(Vec, SilentPaymentAddress, OutPoint)> { let nonce = Nonce::from_slice(&cipher[..12]); for (outpoint, process) in processes.iter() { - for (address, secret) in &process.shared_secrets { - let aes_key = match AnkSharedSecretHash::from_str(secret) { - Ok(key) => key, - Err(_) => continue, - }; - - let engine = Aes256Gcm::new(aes_key.as_byte_array().into()); + for (address, secret) in process.get_all_secrets() { + let engine = Aes256Gcm::new(&secret.to_byte_array().into()); if let Ok(plain) = engine.decrypt( &nonce, Payload { @@ -596,7 +595,7 @@ fn try_decrypt_with_processes( ) { return Some(( plain, - SilentPaymentAddress::try_from(address.as_str()).unwrap(), + address, *outpoint, )); } @@ -655,7 +654,7 @@ pub fn response_prd( }; } -fn confirm_prd(prd: Prd, shared_secret: &str) -> AnyhowResult { +fn confirm_prd(prd: Prd, shared_secret: &AnkSharedSecretHash) -> AnyhowResult { match prd.prd_type { PrdType::Confirm | PrdType::Response | PrdType::List => { return Err(AnyhowError::msg("Invalid prd type")); @@ -690,16 +689,16 @@ fn confirm_prd(prd: Prd, shared_secret: &str) -> AnyhowResult { let prd_msg = prd_confirm.to_network_msg(local_device.get_wallet())?; - Ok(encrypt_with_key(prd_msg, shared_secret.to_owned()).unwrap()) + Ok(encrypt_with_key(shared_secret.as_byte_array(), prd_msg.as_bytes())?.to_lower_hex_string()) } -fn send_data(prd: &Prd, shared_secret: &str) -> AnyhowResult { +fn send_data(prd: &Prd, shared_secret: &AnkSharedSecretHash) -> AnyhowResult { let pcd = &prd.payload; - let cipher = encrypt_with_key(pcd.clone(), shared_secret.to_owned()).unwrap(); + let cipher = encrypt_with_key(shared_secret.as_byte_array(), pcd.as_bytes())?; Ok(ApiReturn { - ciphers_to_send: vec![cipher], + ciphers_to_send: vec![cipher.to_lower_hex_string()], ..Default::default() }) } @@ -767,17 +766,9 @@ fn decrypt_with_known_processes(cipher: &[u8]) -> anyhow::Result let nonce = Nonce::from_slice(&cipher[..12]); for (outpoint, process) in processes.iter() { - for (address, secret) in &process.shared_secrets { + for (address, secret) in process.get_all_secrets() { debug!("Attempting decryption with key {} for {}", secret, address); - let aes_key = match AnkSharedSecretHash::from_str(secret) { - Ok(key) => key, - Err(_) => { - debug!("Invalid shared secret for process {}: {}", outpoint, secret); - continue; - } - }; - - let engine = Aes256Gcm::new(aes_key.as_byte_array().into()); + let engine = Aes256Gcm::new(secret.as_byte_array().into()); if let Ok(plain) = engine.decrypt( &nonce, @@ -832,13 +823,10 @@ fn handle_prd( .ok_or_else(|| anyhow::Error::msg("Missing shared secret for new process"))?; let mut shared_secrets = HashMap::new(); shared_secrets.insert( - sp_address.to_string(), - shared_secret.to_byte_array().to_lower_hex_string(), + sp_address, + shared_secret, ); - entry.insert(RelevantProcess { - shared_secrets, - ..Default::default() - }) + entry.insert(Process::new(vec![], shared_secrets, vec![])) } }; @@ -848,8 +836,8 @@ fn handle_prd( // We send the whole data in a pcd debug!("Received confirm prd {:#?}", prd); let original_request = relevant_process - .impending_requests - .iter() + .get_impending_requests() + .into_iter() .find(|r| { if r.prd_type != PrdType::Update { return false; @@ -859,27 +847,25 @@ fn handle_prd( }) .ok_or(anyhow::Error::msg("Original request not found"))?; let shared_secret = relevant_process - .shared_secrets - .get(&sp_address.to_string()) + .get_shared_secret_for_address(&sp_address) .ok_or(anyhow::Error::msg( "Missing shared secret for address in original request", ))?; - return send_data(original_request, shared_secret); + return send_data(original_request, &shared_secret); } 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.impending_requests.push(prd.clone()); + relevant_process.insert_impending_request(prd.clone()); let shared_secret = relevant_process - .shared_secrets - .get(&sp_address.to_string()) + .get_shared_secret_for_address(&sp_address) .ok_or(anyhow::Error::msg( "Missing shared secret for address in original request", ))?; - let cipher = confirm_prd(prd, shared_secret)?; + let cipher = confirm_prd(prd, &shared_secret)?; return Ok(ApiReturn { ciphers_to_send: vec![cipher], @@ -890,8 +876,8 @@ fn handle_prd( PrdType::Response => { // We must know of a prd update that the response answers to let original_request = relevant_process - .impending_requests - .iter() + .get_impending_requests() + .into_iter() .find(|r| { if r.prd_type != PrdType::Update { return false; @@ -919,8 +905,8 @@ fn handle_pcd(plain: Vec, root_commitment: OutPoint) -> AnyhowResult ApiResult { - let nonce = Aes256Gcm::generate_nonce(&mut rand::thread_rng()); - - let mut aes_key = [0u8; 32]; - aes_key.copy_from_slice(&Vec::from_hex(&key)?); - - // encrypt - let aes_enc = Aes256Encryption::import_key( - Purpose::Arbitrary, - plaintext.into_bytes(), - aes_key, - nonce.into(), - )?; - - let cipher = aes_enc.encrypt_with_aes_key()?; - - Ok(cipher.to_lower_hex_string()) -} - -#[wasm_bindgen] -pub fn encrypt_with_new_key(plaintext: String) -> ApiResult { - let mut rng = rand::thread_rng(); - - // generate new key - let aes_key = Aes256Gcm::generate_key(&mut rng); - let nonce = Aes256Gcm::generate_nonce(&mut rng); - - // encrypt - let aes_enc = Aes256Encryption::import_key( - Purpose::Arbitrary, - plaintext.into_bytes(), - aes_key.into(), - nonce.into(), - )?; - - let cipher = aes_enc.encrypt_with_aes_key()?; - - Ok(encryptWithNewKeyResult { - cipher: cipher.to_lower_hex_string(), - key: aes_key.to_lower_hex_string(), - }) -} - -#[wasm_bindgen] -pub fn try_decrypt_with_key(cipher: String, key: String) -> ApiResult { - let key_bin = Vec::from_hex(&key)?; - if key_bin.len() != 32 { - return Err(ApiError::new("key of invalid lenght".to_owned())); - } - let mut aes_key = [0u8; 32]; - aes_key.copy_from_slice(&Vec::from_hex(&key)?); - let aes_dec = Aes256Decryption::new(Purpose::Arbitrary, Vec::from_hex(&cipher)?, aes_key)?; - - let plain = String::from_utf8(aes_dec.decrypt_with_key()?)?; - Ok(plain) -} - #[wasm_bindgen] pub fn create_faucet_msg() -> ApiResult { let sp_address = lock_local_device()? @@ -1442,8 +1366,8 @@ pub fn get_update_proposals(process_outpoint: String) -> ApiResult> .ok_or(ApiError::new("process not found".to_owned()))?; let update_proposals: Vec<&Prd> = relevant_process - .impending_requests - .iter() + .get_impending_requests() + .into_iter() .filter(|r| r.prd_type == PrdType::Update) .collect(); diff --git a/src/lib.rs b/src/lib.rs index a892a68..188a0bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,21 +1,8 @@ #![allow(warnings)] use anyhow::Error; -use sdk_common::crypto::AnkSharedSecret; use sdk_common::network::CachedMessage; -use sdk_common::pcd::AnkPcdHash; -use sdk_common::prd::Prd; -use sdk_common::process::Process; -use sdk_common::signature::Proof; -use sdk_common::sp_client::bitcoin::OutPoint; -use sdk_common::uuid::Uuid; use sdk_common::MutexExt; -use serde::{Deserialize, Serialize}; -use serde_json::{Map, Value}; -use std::collections::{HashMap, HashSet}; -use std::fmt::Debug; -use std::ops::Index; use std::sync::{Mutex, MutexGuard, OnceLock}; -use tsify::Tsify; pub mod api; mod peers; @@ -29,41 +16,3 @@ pub fn lock_messages() -> Result>, Error> .get_or_init(|| Mutex::new(vec![])) .lock_anyhow() } - -// TODO move to sdk-common -#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] -pub struct ProcessState { - pub commited_in: OutPoint, - pub encrypted_pcd: Value, - pub keys: Map, // We may not always have all the keys - pub validation_token: Vec, // This signs the encrypted pcd -} - -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] -pub struct RelevantProcess { - states: Vec, - shared_secrets: HashMap, - impending_requests: Vec, -} - -impl RelevantProcess { - pub fn get_status_at(&self, index: usize) -> Option { - self.states.get(index).cloned() - } - - pub fn get_latest_state(&self) -> Option { - self.states.last().cloned() - } - - pub fn get_impending_requests(&self) -> Vec { - self.impending_requests.clone() - } -} - -pub static CACHEDPROCESSES: OnceLock>> = OnceLock::new(); - -pub fn lock_processes() -> Result>, Error> { - CACHEDPROCESSES - .get_or_init(|| Mutex::new(HashMap::new())) - .lock_anyhow() -} diff --git a/src/user.rs b/src/user.rs index bab7706..6097f17 100644 --- a/src/user.rs +++ b/src/user.rs @@ -9,7 +9,6 @@ use sdk_common::sp_client::bitcoin::{ Network, OutPoint, ScriptBuf, Transaction, Txid, XOnlyPublicKey, }; use sdk_common::sp_client::spclient::SpClient; -use sdk_common::uuid::Uuid; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use tsify::Tsify; @@ -31,9 +30,7 @@ use sdk_common::sp_client::spclient::{OutputList, SpWallet, SpendKey}; use crate::peers::Peer; use crate::wallet::generate_sp_wallet; use crate::MutexExt; -use sdk_common::crypto::{ - AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, HalfKey, KeyInit, Purpose, -}; +use sdk_common::crypto::{AeadCore, Aes256Gcm, KeyInit}; pub static LOCAL_DEVICE: OnceLock> = OnceLock::new(); diff --git a/tests/pairing.rs b/tests/pairing.rs index affc254..77a1bc4 100644 --- a/tests/pairing.rs +++ b/tests/pairing.rs @@ -57,12 +57,12 @@ fn test_pairing() { "validation_rules": [ { - "quorum": 0.0, + "quorum": 1.0, "fields": [ "roles", "pairing_tx" ], - "min_sig_member": 0.0 + "min_sig_member": 1.0 } ] } @@ -114,7 +114,6 @@ fn test_pairing() { // TODO unpair device // We can produce the prd response now even if we can't use it yet - // TODO pass the process as argument let alice_prd_response = response_prd( root_outpoint, alice_init_process @@ -130,6 +129,8 @@ fn test_pairing() { .unwrap() .clone(); + // We can also create the first login transaction and sign it + // this is only for testing, as we're playing both parts let alice_device = dump_device().unwrap(); let alice_processes = dump_process_cache().unwrap(); @@ -263,6 +264,15 @@ fn test_pairing() { .unwrap(); // To make the pairing effective, alice and bob must now creates a new transaction where they both control one output + + // login logic: user must have access to both devices to login + // user must still have access to both devices in case an action needs both devices (as defined in the roles) + // process can define that acting on some fields of the state only needs a fraction of the devices to sign + + // Problem: we need both devices to sign the next login transaction. + // Simplest solution: device A creates the transaction with both inputs and outputs, signs its input and sends to device B + // device B notify user that a login is underway, user either accepts (sign the transaction and broadcast), or refuses (actually we should think of some revokation step from here) + // login(); // Once we know this tx id, we can commit to the relay diff --git a/tests/utils.rs b/tests/utils.rs index 63e5ce5..177d7bb 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use sdk_client::api::{parse_cipher, parse_new_tx, ApiResult, ApiReturn}; +use sdk_client::api::{parse_new_tx, ApiReturn}; use sdk_common::network::NewTxMessage; use sdk_common::sp_client::bitcoin::consensus::serialize; use sdk_common::sp_client::bitcoin::hex::DisplayHex; @@ -17,22 +17,6 @@ pub const ALICE_START_WALLET: &str = "{\"client\":{\"network\":\"regtest\",\"lab pub const ALICE_LOGIN_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}}}},\"tx_history\":[]}"; pub const BOB_START_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; pub const BOB_LOGIN_WALLET: &str = "{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; -pub const ALICE_ANSWER_CACHE: &str = "[{\"id\":1436790358,\"status\":\"MustSpendConfirmation\",\"prd_cipher\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590537,\"error\":null}]"; -pub const ALICE_FINAL_CACHE: &str = "[{\"id\":1436790358,\"status\":\"Trusted\",\"prd_cipher\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590537,\"error\":null}]"; -pub const BOB_ANSWER_CACHE: &str = "[{\"id\":2887008190,\"status\":\"ReceivedMustConfirm\",\"prd_cipher\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\",\"timestamp\":1723198590605,\"error\":null}]"; -pub const BOB_PAIRING_CACHE: &str = "[{\"id\":2853916441,\"status\":\"Pairing\",\"prd_cipher\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\",\"tied_by\":null,\"commitment\":\"7f340cd5f070a4bd8d16077214a0488e43bd41d64d8b2b39ab0fc016c1093eba\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"a86c30250a8e6a8dc9581b3ab2dacafda6446f6c65f4debe124f5870b6796ea1\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062445,\"error\":null}, {\"id\":1045548533,\"status\":\"Closed\",\"prd_cipher\":\"bd2acbc73fc402a8cb57121153f2667b944fe31f67ccdd6031e7d9481642f42ebdae00b572b1be6735ff413ceedccf29d2f0700021c6cf61b954891912968a449e6cb735e9344d90db21268ff596f844db358bc4852358ac89a71e81179b249b499a6b70bef341ff71737ea0a9a7e3f2a90bb41d376272410a18ec367d5b6f417420d6d6ee06a132c263269cba281c1fa6e644b5beed716783e973594f5e9da76c28bdc10968ec7e49031924fb8051ec80d27f87e943f884263cb1a273b18f79\",\"plaintext\":[\"PAIRING\"],\"commited_in\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\",\"tied_by\":1,\"commitment\":\"213c1295d6721f3194745063190487e73853c21373218255d2af20c4b1ba6a7b\",\"sender\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"recipient\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"shared_secret\":\"094849bcf340d0791fa0bae31c9b58b8572ad3c9bd028de3a26e501b578cb24b\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062534,\"error\":null}]"; -pub const ALICE_PAIRING_CACHE: &str = "[{\"id\":2059106889,\"status\":\"Closed\",\"prd_cipher\":\"6634050737f9dc18b187c69872943f9a11764252bac9e163fcb7480fd0aa3cf543f7b0b7eef9579d1ddba0b79fdf8c59747050313d0518ea4c8d23d2665948549efd72d0fde7bc8e7a02936de78b7406a31072429d9a81751d5665e9333f8c429c59e47a11b8993583fc5806c8e8695db970247761d11782188c550bd19f7a2c60172104c2892a463f79c19e4173852279012003edf3f777e7c1a95e7d87863d155bcaee1fc4c1b0cb69cab42a45ad5c6271a9c9ba4f79e49a3de2e0fa0aa9bc\",\"plaintext\":[\"PAIRING\"],\"commited_in\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\",\"tied_by\":1,\"commitment\":\"7f340cd5f070a4bd8d16077214a0488e43bd41d64d8b2b39ab0fc016c1093eba\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"a86c30250a8e6a8dc9581b3ab2dacafda6446f6c65f4debe124f5870b6796ea1\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062375,\"error\":null}, {\"id\":3841225687,\"status\":\"Pairing\",\"prd_cipher\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\",\"tied_by\":null,\"commitment\":\"213c1295d6721f3194745063190487e73853c21373218255d2af20c4b1ba6a7b\",\"sender\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"recipient\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"shared_secret\":\"094849bcf340d0791fa0bae31c9b58b8572ad3c9bd028de3a26e501b578cb24b\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062605,\"error\":null}]"; -pub const ALICE_CHALLENGE_CACHE: &str = "[{\"id\":1436790358,\"status\":\"SentWaitingConfirmation\",\"prd_cipher\":\"05ec465a397eee0e6a01884010dace55ccb539413e46f12ac760ba811e206e22df9fc621ccb21c2485b548281e668eec8e6a814d509ce6b99febc40036d5f763f86f26f0db52badf0e662cb7533f5298afb09e2fe8624af126c90102084888bcd1d17c9419a045a73d983f3fb2825681d9c25d5875bc77c95eb016bf5df70123753e181078a6101f777e19b0d3d27f1032ee050c7b3635b039b5c94cb93b83c499ffacf8eb56b4d1ba693f8e1fb2e466761169af63222155f250ee1c80\",\"plaintext\":[\"TEST\"],\"commited_in\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"ef89aabce6639a82436c10083dfaccf152aeb7c16731e7e639866da1c86d2fd9\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1723198590537,\"error\":null}]"; -pub const BOB_CHALLENGE_CACHE: &str = "[{\"id\":3192205787,\"status\":\"ReceivedMustConfirm\",\"commited_in\":\"662e6513e108fc6c0abea3da59c9c710c44c3d7cf81973398c526bbd1d6f69e5:0\",\"tied_by\":null,\"commitment\":\"b5aa9b3bc455c56070269904271b798e50b3076fdbbc7bbfcf4cb44c7cf21bc7\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"4d71a5e617a3bd6923ea1bac26e6d9981edbd1615556264c1271458172337003\",\"prd_cipher\":null,\"prd\":{\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"key\":[84,186,61,88,197,78,128,88,176,85,201,247,228,113,97,153,123,129,14,22,10,134,122,221,61,134,54,12,65,5,162,45],\"pcd_commitment\":\"8eec815cc389b7c5ff573533620051fbb97ba025bd0cf3cb2e903b632652fd2b\",\"error\":null},\"pcd_cipher\":null,\"pcd\":{\"message\":\"TEST\",\"error\":null},\"pcd_commitment\":\"8eec815cc389b7c5ff573533620051fbb97ba025bd0cf3cb2e903b632652fd2b\",\"confirmed_by\":null,\"timestamp\":1723724725299,\"error\":null}]"; -pub const ALICE_PAIRED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\"}}"; -pub const BOB_PAIRED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\"}}"; -pub const ALICE_LOGGED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; -pub const BOB_LOGGED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; -pub const ALICE_CHALLENGE_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; -pub const BOB_CHALLENGE_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"0754a8c68a836ee37e00a4fbc6109bd10558bae0f83eaea31efec3a16dc7ac68:0\":{\"blockheight\":0,\"tweak\":\"77db25e5a74948afe852209cdd84445708bf71d2a2465d4feb81075b4864aa62\",\"amount\":1200,\"script\":\"5120c11362725586664cd5001737afde129c61b82f16c0a661972453e423e937c91c\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; -pub const ALICE_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":\"Unspent\"},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\":{\"blockheight\":0,\"tweak\":\"de507c854cee16d2e157fbf6c6dbfd2e721b861efc7f657bb724790fc7829665\",\"amount\":349,\"script\":\"5120028143243ed5d4554e60d96ee61fdf6f6e359a9083311c210645c0a7fef51248\",\"label\":null,\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; -pub const BOB_ANSWER_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:1\":{\"blockheight\":0,\"tweak\":\"281ea54f74e5f6582a7462bdd9397b9a786f97455e858e7901a6a4fa95f39192\",\"amount\":654,\"script\":\"5120aa4395e2be9cbce580e94f4308d64422da251b7df12fb8c571675d40cc50cf00\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:0\":{\"blockheight\":0,\"tweak\":\"21fc32bded971dd15387671436232f17d932e18758f69b476219e2d6e688767f\",\"amount\":1200,\"script\":\"5120230d06322d10a5838634df3c55eef9959a1c0c144108e0416b9687eaf22e6baa\",\"label\":null,\"spend_status\":{\"Spent\":\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; -pub const ALICE_FINAL_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"650088ebc28e4d5d7b4ee2e0337b4907a02537f5be6c28c63da88a6b67b9af1d:0\":{\"blockheight\":0,\"tweak\":\"de507c854cee16d2e157fbf6c6dbfd2e721b861efc7f657bb724790fc7829665\",\"amount\":349,\"script\":\"5120028143243ed5d4554e60d96ee61fdf6f6e359a9083311c210645c0a7fef51248\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:1\":{\"blockheight\":0,\"tweak\":\"97b06ded6644c6ae2a861342db3375d10a002da72f367a0acd5b8890c277df1e\",\"amount\":248,\"script\":\"5120902e75b33f6a80f20edd2574f02f5eaf3fc196aaad9c494263465519606a47a7\",\"label\":null,\"spend_status\":{\"Spent\":\"f07c116303c88e7b22169f0872c67e3196ad8312170313643a8f47482c6bd308\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2\"}},\"494aa6088c4ff368c04ee9dcacad8ab20d91587bacd48e030ab510b012131fe2:2\":{\"blockheight\":0,\"tweak\":\"6493d306b4650a36321d05270e2067b58839637da52f0fc29cd2f05817fff0d6\",\"amount\":3933896,\"script\":\"51206666fc11233881b1c831e032e9b06cf05a90ed93fef4f35c78583b9eec845ab5\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; pub const RELAY_ADDRESS: &str = "sprt1qqfmqt0ngq99y8t4ke6uhtm2a2vc2zxvhj7hjrqu599kn30d4cs9rwqn6n079mdr4dfqg72yrtvuxf43yswscw86nvvl09mc5ljx65vfh75fkza35"; pub const DEFAULT_NYM: &str = "AliceBob"; From 589e8d1d1de3623aa89d2e173e722c05023bea15 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Wed, 25 Sep 2024 17:06:27 +0200 Subject: [PATCH 11/14] Change new_tx return type to String --- src/api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api.rs b/src/api.rs index f9327f0..35ed78d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -84,7 +84,7 @@ use crate::{ pub struct ApiReturn { pub updated_cached_msg: Vec, pub updated_process: Option<(String, Process)>, - pub new_tx_to_send: Option, + pub new_tx_to_send: Option, pub ciphers_to_send: Vec, pub commit_to_send: Option, } @@ -1324,7 +1324,7 @@ pub fn create_update_transaction( }); Ok(ApiReturn { - new_tx_to_send: Some(final_tx), + new_tx_to_send: Some(serialize(&final_tx).to_lower_hex_string()), updated_process: Some((commitment_outpoint.to_string(), relevant_process.clone())), ciphers_to_send: ciphers, ..Default::default() From 0dc14dee4ad3430581aa9db87bf2cb82ab056fc9 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Thu, 26 Sep 2024 10:45:01 +0200 Subject: [PATCH 12/14] create_update_transaction returns NewTxMessage --- src/api.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api.rs b/src/api.rs index 35ed78d..c99c91f 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1323,8 +1323,11 @@ pub fn create_update_transaction( validation_token: vec![], }); + // Create the new_tx message + let new_tx_msg = NewTxMessage::new(serialize(&final_tx).to_lower_hex_string(), None); + Ok(ApiReturn { - new_tx_to_send: Some(serialize(&final_tx).to_lower_hex_string()), + new_tx_to_send: Some(new_tx_msg), updated_process: Some((commitment_outpoint.to_string(), relevant_process.clone())), ciphers_to_send: ciphers, ..Default::default() From 4bd139330683393ff696bd6d58007450850e16b8 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Fri, 27 Sep 2024 12:44:10 +0200 Subject: [PATCH 13/14] fix pairing test --- tests/pairing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pairing.rs b/tests/pairing.rs index 77a1bc4..3e2ef31 100644 --- a/tests/pairing.rs +++ b/tests/pairing.rs @@ -257,7 +257,7 @@ fn test_pairing() { pair_device(pairing_tx.to_owned(), proposal_members).unwrap(); // Bob signs the proposal and sends a prd response too - let bob_prd_response = response_prd(root_commitment, pcd_commitment, true) + let bob_prd_response = response_prd(root_commitment, prd_update.get_impending_requests().get(0).unwrap().to_string(), true) .unwrap() .ciphers_to_send .get(0) From 6566f4c192f1aaab80b332a324ee63c299da24da Mon Sep 17 00:00:00 2001 From: Sosthene Date: Fri, 27 Sep 2024 15:13:23 +0200 Subject: [PATCH 14/14] fix pairing tests --- tests/pairing.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/pairing.rs b/tests/pairing.rs index 3e2ef31..a4917de 100644 --- a/tests/pairing.rs +++ b/tests/pairing.rs @@ -196,10 +196,12 @@ fn test_pairing() { debug!("bob_parsed_pcd: {:#?}", bob_parsed_pcd_return); + let (root_commitment, prd_update) = bob_parsed_pcd_return.updated_process.unwrap(); + // At this point, user must validate the pairing proposal received from Alice // We decrypt the content of the pcd so that we can display to user what matters let alice_proposal = - get_update_proposals(bob_parsed_pcd_return.updated_process.unwrap().0).unwrap(); + get_update_proposals(root_commitment.clone()).unwrap(); debug!("Alice proposal: {:#?}", alice_proposal); @@ -254,10 +256,12 @@ fn test_pairing() { // we can now show all the addresses + pairing tx to the user on device to prompt confirmation debug!("Bob pairs device with Alice"); - pair_device(pairing_tx.to_owned(), proposal_members).unwrap(); + pair_device(pairing_tx.to_owned(), proposal_members.clone()).unwrap(); + + let prd_to_respond = prd_update.get_impending_requests().get(0).unwrap().to_string(); // Bob signs the proposal and sends a prd response too - let bob_prd_response = response_prd(root_commitment, prd_update.get_impending_requests().get(0).unwrap().to_string(), true) + let bob_prd_response = response_prd(root_commitment, prd_to_respond, true) .unwrap() .ciphers_to_send .get(0)