diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 2d3417c..f0b838e 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,14 +1,11 @@ use std::collections::HashMap; use anyhow::Result; -use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transaction::Tag}; +use common::{merkle_tree_public::TreeHashType, transaction::Tag}; use k256::AffinePoint; use log::info; use serde::Serialize; -use utxo::{ - utxo_core::{UTXOPayload, UTXO}, - utxo_tree::UTXOSparseMerkleTree, -}; +use utxo::utxo_core::UTXO; use crate::key_management::{ constants_types::{CipherText, Nonce}, @@ -23,7 +20,7 @@ pub struct Account { pub key_holder: AddressKeyHolder, pub address: AccountAddress, pub balance: u64, - pub utxo_tree: UTXOSparseMerkleTree, + pub utxos: HashMap, } ///A strucure, which represents all the visible(public) information @@ -42,26 +39,30 @@ impl Account { let key_holder = AddressKeyHolder::new_os_random(); let address = key_holder.address; let balance = 0; - let utxo_tree = UTXOSparseMerkleTree::new(); + let utxos = HashMap::new(); Self { key_holder, address, balance, - utxo_tree, + utxos, } } + pub fn get_utxo_by_hash(&self, utxo_hash: TreeHashType) -> Option<&UTXO> { + self.utxos.get(&utxo_hash) + } + pub fn new_with_balance(balance: u64) -> Self { let key_holder = AddressKeyHolder::new_os_random(); let address = key_holder.address; - let utxo_tree = UTXOSparseMerkleTree::new(); + let utxo_tree = HashMap::new(); Self { key_holder, address, balance, - utxo_tree, + utxos: utxo_tree, } } @@ -87,47 +88,20 @@ impl Account { .decrypt_data(ephemeral_public_key_sender, ciphertext, nonce) } - pub fn mark_spent_utxo( - &mut self, - utxo_nullifier_map: HashMap, - ) -> Result<()> { - for (hash, nullifier) in utxo_nullifier_map { - if let Some(utxo_entry) = self.utxo_tree.store.get_mut(&hash) { - utxo_entry.consume_utxo(nullifier)?; - } - } - - Ok(()) - } - pub fn add_new_utxo_outputs(&mut self, utxos: Vec) -> Result<()> { - Ok(self.utxo_tree.insert_items(utxos)?) + for utxo in utxos { + if self.utxos.contains_key(&utxo.hash) { + return Err(anyhow::anyhow!("UTXO already exists")); + } + self.utxos.insert(utxo.hash, utxo); + } + return Ok(()); } pub fn update_public_balance(&mut self, new_balance: u64) { self.balance = new_balance; } - pub fn add_asset( - &mut self, - asset: Asset, - amount: u128, - privacy_flag: bool, - ) -> Result<()> { - let payload_with_asset = UTXOPayload { - owner: self.address, - asset: serde_json::to_vec(&asset)?, - amount, - privacy_flag, - }; - - let asset_utxo = UTXO::create_utxo_from_payload(payload_with_asset)?; - - self.utxo_tree.insert_item(asset_utxo)?; - - Ok(()) - } - pub fn log(&self) { info!("Keys generated"); info!("Account address is {:?}", hex::encode(self.address)); @@ -157,11 +131,9 @@ impl Default for Account { #[cfg(test)] mod tests { - use super::*; + use utxo::utxo_core::UTXOPayload; - fn generate_dummy_utxo_nullifier() -> UTXONullifier { - UTXONullifier::default() - } + use super::*; fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> anyhow::Result { let payload = UTXOPayload { @@ -181,21 +153,6 @@ mod tests { assert!(account.key_holder.address != [0u8; 32]); // Check if the address is not empty } - #[test] - fn test_mark_spent_utxo() { - let mut account = Account::new(); - let utxo = generate_dummy_utxo(account.address, 100).unwrap(); - account.add_new_utxo_outputs(vec![utxo]).unwrap(); - - let mut utxo_nullifier_map = HashMap::new(); - utxo_nullifier_map.insert(account.address, generate_dummy_utxo_nullifier()); - - let result = account.mark_spent_utxo(utxo_nullifier_map); - - assert!(result.is_ok()); - assert!(account.utxo_tree.store.get(&account.address).is_none()); - } - #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); @@ -205,7 +162,7 @@ mod tests { let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]); assert!(result.is_ok()); - assert_eq!(account.utxo_tree.store.len(), 2); + assert_eq!(account.utxos.len(), 2); } #[test] @@ -215,16 +172,4 @@ mod tests { assert_eq!(account.balance, 500); } - - #[test] - fn test_add_asset() { - let mut account = Account::new(); - let asset = "dummy_asset"; - let amount = 1000u128; - - let result = account.add_asset(asset, amount, false); - - assert!(result.is_ok()); - assert_eq!(account.utxo_tree.store.len(), 1); - } } diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index f8bcf4e..3abe0b1 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -125,7 +125,7 @@ impl NodeChainStore { serde_json::from_slice::(&decoded_data_curr_acc); if let Ok(utxo) = decoded_utxo_try { if &utxo.owner == acc_id { - acc.utxo_tree.insert_item(utxo)?; + acc.utxos.insert(utxo.hash, utxo); } } } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index c0a97e5..e4b1613 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -1058,11 +1058,15 @@ impl NodeCore { tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; let new_utxo = { - let mut write_guard = self.storage.write().await; + let read_guard = self.storage.read().await; - let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); + let acc = read_guard.acc_map.get(&acc_addr).unwrap(); - acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone() + acc.get_utxo_by_hash(new_utxo_hash) + .ok_or(ExecutionFailureKind::DBError(anyhow::anyhow!( + "Minted UTXO did not land" + )))? + .clone() }; new_utxo.log(); @@ -1079,55 +1083,6 @@ impl NodeCore { Ok((new_utxo, comm_gen_hash)) } - pub async fn operate_account_mint_multiple_assets_private( - &mut self, - acc_addr: AccountAddress, - amount: u128, - number_of_assets: usize, - ) -> Result<(Vec, Vec<[u8; 32]>), ExecutionFailureKind> { - let (resp, new_utxo_hashes, comm_gen_hashes) = self - .send_private_mint_multiple_assets_tx(acc_addr, amount, number_of_assets) - .await?; - info!("Response for mint multiple assets private is {resp:?}"); - - info!("Awaiting new blocks"); - tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; - - let new_utxos = { - let mut write_guard = self.storage.write().await; - - new_utxo_hashes - .into_iter() - .map(|new_utxo_hash| { - let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); - - let new_utxo = acc - .utxo_tree - .get_item(new_utxo_hash) - .unwrap() - .unwrap() - .clone(); - - new_utxo.log(); - info!( - "Account address is {:?} ,new utxo owner address is {:?}", - hex::encode(acc_addr), - hex::encode(new_utxo.owner) - ); - info!( - "Account {:?} got new utxo with amount {amount:?} and asset {:?}", - hex::encode(acc_addr), - new_utxo.asset - ); - - new_utxo - }) - .collect() - }; - - Ok((new_utxos, comm_gen_hashes)) - } - pub async fn operate_account_send_deshielded_one_receiver( &mut self, acc_addr_rec: AccountAddress, @@ -1233,12 +1188,16 @@ impl NodeCore { tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; let new_utxo = { - let mut write_guard = self.storage.write().await; + let read_guard = self.storage.read().await; - let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); + let acc = read_guard.acc_map.get(&acc_addr_rec).unwrap(); acc.log(); - acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone() + acc.get_utxo_by_hash(new_utxo_hash) + .ok_or(ExecutionFailureKind::DBError(anyhow::anyhow!( + "Minted UTXO did not land" + )))? + .clone() }; new_utxo.log(); info!( @@ -1273,12 +1232,16 @@ impl NodeCore { tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; let new_utxo = { - let mut write_guard = self.storage.write().await; + let read_guard = self.storage.read().await; - let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); + let acc = read_guard.acc_map.get(&acc_addr_rec).unwrap(); acc.log(); - acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone() + acc.get_utxo_by_hash(new_utxo_hash) + .ok_or(ExecutionFailureKind::DBError(anyhow::anyhow!( + "Minted UTXO did not land" + )))? + .clone() }; new_utxo.log(); info!( @@ -1317,13 +1280,18 @@ impl NodeCore { tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; { - let mut write_guard = self.storage.write().await; + let read_guard = self.storage.read().await; for new_utxo_hash in new_utxo_hashes_rec { - let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); + let acc = read_guard.acc_map.get(&acc_addr_rec).unwrap(); acc.log(); - let new_utxo = acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone(); + let new_utxo = acc + .get_utxo_by_hash(new_utxo_hash) + .ok_or(ExecutionFailureKind::DBError(anyhow::anyhow!( + "Minted UTXO did not land" + )))? + .clone(); new_utxo.log(); info!( @@ -1340,10 +1308,15 @@ impl NodeCore { } for new_utxo_hash in new_utxo_hashes_not_sp { - let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); + let acc = read_guard.acc_map.get(&acc_addr).unwrap(); acc.log(); - let new_utxo = acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone(); + let new_utxo = acc + .get_utxo_by_hash(new_utxo_hash) + .ok_or(ExecutionFailureKind::DBError(anyhow::anyhow!( + "Minted UTXO did not land" + )))? + .clone(); new_utxo.log(); info!( @@ -1549,19 +1522,14 @@ impl NodeCore { tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; let new_utxos: Vec = { - let mut write_guard = self.storage.write().await; + let read_guard = self.storage.read().await; new_utxo_hashes .into_iter() .map(|(acc_addr_rec, new_utxo_hash)| { - let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); + let acc = read_guard.acc_map.get(&acc_addr_rec).unwrap(); - let new_utxo = acc - .utxo_tree - .get_item(new_utxo_hash) - .unwrap() - .unwrap() - .clone(); + let new_utxo = acc.get_utxo_by_hash(new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( @@ -1686,31 +1654,6 @@ impl NodeCore { Ok(()) } - - ///Mint number of different assets with same amount for account - pub async fn scenario_2( - &mut self, - number_of_assets: usize, - number_to_send: usize, - ) -> Result<(), ExecutionFailureKind> { - let acc_addr_sender = self.create_new_account().await; - let acc_addr_receiver = self.create_new_account().await; - - let (utxos, comm_gen_hashes) = self - .operate_account_mint_multiple_assets_private(acc_addr_sender, 100, number_of_assets) - .await?; - - self.operate_account_send_private_multiple_assets_one_receiver( - acc_addr_sender, - acc_addr_receiver, - utxos, - comm_gen_hashes, - number_to_send, - ) - .await?; - - Ok(()) - } } pub fn generate_commitments_helper(input_utxos: &[UTXO]) -> Vec<[u8; 32]> { diff --git a/node_rpc/src/process.rs b/node_rpc/src/process.rs index 38621ba..42d5b96 100644 --- a/node_rpc/src/process.rs +++ b/node_rpc/src/process.rs @@ -18,14 +18,12 @@ use common::rpc_primitives::requests::{ use crate::types::{ err_rpc::cast_common_execution_error_into_rpc_error, rpc_structs::{ - CreateAccountRequest, CreateAccountResponse, ExecuteScenarioMultipleSendRequest, - ExecuteScenarioMultipleSendResponse, ExecuteScenarioSplitRequest, + CreateAccountRequest, CreateAccountResponse, ExecuteScenarioSplitRequest, ExecuteScenarioSplitResponse, ExecuteSubscenarioRequest, ExecuteSubscenarioResponse, ShowAccountPublicBalanceRequest, ShowAccountPublicBalanceResponse, ShowAccountUTXORequest, ShowAccountUTXOResponse, ShowTransactionRequest, ShowTransactionResponse, UTXOShortEssentialStruct, WriteDepositPublicBalanceRequest, - WriteDepositPublicBalanceResponse, WriteMintPrivateUTXOMultipleAssetsRequest, - WriteMintPrivateUTXOMultipleAssetsResponse, WriteMintPrivateUTXORequest, + WriteDepositPublicBalanceResponse, WriteMintPrivateUTXORequest, WriteMintPrivateUTXOResponse, WriteSendDeshieldedBalanceRequest, WriteSendDeshieldedUTXOResponse, WriteSendPrivateUTXORequest, WriteSendPrivateUTXOResponse, WriteSendShieldedUTXORequest, WriteSendShieldedUTXOResponse, WriteSendSplitUTXOResponse, @@ -133,28 +131,6 @@ impl JsonHandler { respond(helperstruct) } - async fn process_request_execute_scenario_multiple_send( - &self, - request: Request, - ) -> Result { - let req = ExecuteScenarioMultipleSendRequest::parse(Some(request.params))?; - - { - let mut store = self.node_chain_store.lock().await; - - store - .scenario_2(req.number_of_assets, req.number_to_send) - .await - .map_err(cast_common_execution_error_into_rpc_error)?; - } - - let helperstruct = ExecuteScenarioMultipleSendResponse { - scenario_result: SUCCESS.to_string(), - }; - - respond(helperstruct) - } - async fn process_create_account(&self, request: Request) -> Result { let _req = CreateAccountRequest::parse(Some(request.params))?; @@ -268,15 +244,8 @@ impl JsonHandler { .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; let utxo = acc - .utxo_tree - .get_item(utxo_hash) - .map_err(|err| { - RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) - })? - .ok_or(RpcError::new_internal_error( - None, - "UTXO does not exist in the tree", - ))?; + .get_utxo_by_hash(utxo_hash) + .ok_or(RpcError::new_internal_error(None, "UTXO does not exist"))?; (utxo.asset.clone(), utxo.amount) } @@ -420,49 +389,6 @@ impl JsonHandler { respond(helperstruct) } - pub async fn process_write_mint_utxo_multiple_assets( - &self, - request: Request, - ) -> Result { - let req = WriteMintPrivateUTXOMultipleAssetsRequest::parse(Some(request.params))?; - - let acc_addr_hex_dec = hex::decode(req.account_addr.clone()).map_err(|_| { - RpcError::parse_error("Failed to decode account address from hex string".to_string()) - })?; - - let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| { - RpcError::parse_error("Failed to parse account address from bytes".to_string()) - })?; - - let (utxos, commitment_hashes) = { - let mut cover_guard = self.node_chain_store.lock().await; - - cover_guard - .operate_account_mint_multiple_assets_private( - acc_addr, - req.amount as u128, - req.num_of_assets, - ) - .await - .map_err(cast_common_execution_error_into_rpc_error)? - }; - - let helperstruct = WriteMintPrivateUTXOMultipleAssetsResponse { - status: SUCCESS.to_string(), - utxos: utxos - .into_iter() - .zip(commitment_hashes) - .map(|(utxo, comm_hash)| UTXOShortEssentialStruct { - hash: hex::encode(utxo.hash), - commitment_hash: hex::encode(comm_hash), - asset: utxo.asset, - }) - .collect(), - }; - - respond(helperstruct) - } - pub async fn process_write_send_private_utxo(&self, request: Request) -> Result { let req = WriteSendPrivateUTXORequest::parse(Some(request.params))?; @@ -512,11 +438,7 @@ impl JsonHandler { .get_mut(&acc_addr_sender) .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; - acc.utxo_tree - .get_item(utxo_hash) - .map_err(|err| { - RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) - })? + acc.get_utxo_by_hash(utxo_hash) .ok_or(RpcError::new_internal_error( None, "UTXO does not exist in tree", @@ -647,11 +569,7 @@ impl JsonHandler { .get_mut(&acc_addr_sender) .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; - acc.utxo_tree - .get_item(utxo_hash) - .map_err(|err| { - RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) - })? + acc.get_utxo_by_hash(utxo_hash) .ok_or(RpcError::new_internal_error( None, "UTXO does not exist in tree", @@ -735,11 +653,7 @@ impl JsonHandler { .get_mut(&acc_addr_sender) .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; - acc.utxo_tree - .get_item(utxo_hash) - .map_err(|err| { - RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) - })? + acc.get_utxo_by_hash(utxo_hash) .ok_or(RpcError::new_internal_error( None, "UTXO does not exist in tree", @@ -782,10 +696,6 @@ impl JsonHandler { GET_BLOCK => self.process_get_block_data(request).await, GET_LAST_BLOCK => self.process_get_last_block(request).await, EXECUTE_SCENARIO_SPLIT => self.process_request_execute_scenario_split(request).await, - EXECUTE_SCENARIO_MULTIPLE_SEND => { - self.process_request_execute_scenario_multiple_send(request) - .await - } SHOW_ACCOUNT_PUBLIC_BALANCE => self.process_show_account_public_balance(request).await, SHOW_ACCOUNT_UTXO => self.process_show_account_utxo_request(request).await, SHOW_TRANSACTION => self.process_show_transaction(request).await, @@ -793,9 +703,6 @@ impl JsonHandler { self.process_write_deposit_public_balance(request).await } WRITE_MINT_UTXO => self.process_write_mint_utxo(request).await, - WRITE_MINT_UTXO_MULTIPLE_ASSETS => { - self.process_write_mint_utxo_multiple_assets(request).await - } WRITE_SEND_UTXO_PRIVATE => self.process_write_send_private_utxo(request).await, WRITE_SEND_UTXO_SHIELDED => self.process_write_send_shielded_utxo(request).await, WRITE_SEND_UTXO_DESHIELDED => self.process_write_send_deshielded_utxo(request).await, diff --git a/sc_core/src/lib.rs b/sc_core/src/lib.rs index 769813d..a41ab82 100644 --- a/sc_core/src/lib.rs +++ b/sc_core/src/lib.rs @@ -1,4 +1,3 @@ pub mod cryptography; pub mod proofs_circuits; pub mod transaction_payloads_tools; -pub mod utxo_manipulator; diff --git a/sc_core/src/utxo_manipulator.rs b/sc_core/src/utxo_manipulator.rs deleted file mode 100644 index 8bc0e32..0000000 --- a/sc_core/src/utxo_manipulator.rs +++ /dev/null @@ -1,110 +0,0 @@ -use anyhow::Result; -use common::nullifier::UTXONullifier; -use utxo::utxo_core::{UTXOPayload, UTXO}; - -pub fn utxo_change_owner( - utxo: &mut UTXO, - nullifier: UTXONullifier, - new_owner: [u8; 32], -) -> Result { - let new_payload = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount: utxo.amount, - privacy_flag: utxo.privacy_flag, - }; - - utxo.consume_utxo(nullifier)?; - - Ok(UTXO::create_utxo_from_payload(new_payload)?) -} - -pub fn utxo_substact_part_another_owner( - utxo: &mut UTXO, - nullifier: UTXONullifier, - amount: u128, - new_owner: [u8; 32], -) -> Result<(UTXO, UTXO)> { - if amount > utxo.amount { - anyhow::bail!("Amount too big"); - } - - let diff = utxo.amount - amount; - - let new_payload1 = UTXOPayload { - owner: utxo.owner, - asset: utxo.asset.clone(), - amount: diff, - privacy_flag: utxo.privacy_flag, - }; - - let new_payload2 = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount, - privacy_flag: utxo.privacy_flag, - }; - - utxo.consume_utxo(nullifier)?; - - Ok(( - UTXO::create_utxo_from_payload(new_payload1)?, - UTXO::create_utxo_from_payload(new_payload2)?, - )) -} - -pub fn utxo_substract_part( - utxo: &mut UTXO, - nullifier: UTXONullifier, - amount: u128, -) -> Result<(UTXO, UTXO)> { - let new_owner = utxo.owner; - - utxo_substact_part_another_owner(utxo, nullifier, amount, new_owner) -} - -pub fn utxo_split_n_users( - utxo: &mut UTXO, - nullifier: UTXONullifier, - users_amounts: Vec<([u8; 32], u128)>, -) -> Result> { - let cumulative_diff = users_amounts - .iter() - .fold(0, |acc, (_, amount)| acc + *amount); - - if cumulative_diff > utxo.amount { - anyhow::bail!("Amount too big"); - } - - let mut utxo_res = vec![]; - - for (new_owner, amount) in users_amounts { - let new_payload = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount, - privacy_flag: utxo.privacy_flag, - }; - - let new_utxo = UTXO::create_utxo_from_payload(new_payload)?; - - utxo_res.push(new_utxo); - } - - if cumulative_diff != utxo.amount { - let new_payload = UTXOPayload { - owner: utxo.owner, - asset: utxo.asset.clone(), - amount: utxo.amount - cumulative_diff, - privacy_flag: utxo.privacy_flag, - }; - - let new_utxo = UTXO::create_utxo_from_payload(new_payload)?; - - utxo_res.push(new_utxo); - } - - utxo.consume_utxo(nullifier)?; - - Ok(utxo_res) -} diff --git a/utxo/src/lib.rs b/utxo/src/lib.rs index 1b7e30c..7baf984 100644 --- a/utxo/src/lib.rs +++ b/utxo/src/lib.rs @@ -1,2 +1 @@ pub mod utxo_core; -pub mod utxo_tree; diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index a4777b3..fd74703 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, AccountId}; +use common::{merkle_tree_public::TreeHashType, AccountId}; use log::info; use serde::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Digest}; @@ -7,12 +7,11 @@ use sha2::{digest::FixedOutput, Digest}; ///Raw asset data pub type Asset = Vec; -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash)] ///Container for raw utxo payload pub struct UTXO { pub hash: TreeHashType, pub owner: AccountId, - pub nullifier: Option, pub asset: Asset, // TODO: change to u256 pub amount: u128, @@ -41,23 +40,12 @@ impl UTXO { Ok(Self { hash, owner: payload_with_asset.owner, - nullifier: None, asset: payload_with_asset.asset, amount: payload_with_asset.amount, privacy_flag: payload_with_asset.privacy_flag, }) } - pub fn consume_utxo(&mut self, nullifier: UTXONullifier) -> Result<()> { - if self.nullifier.is_some() { - anyhow::bail!("UTXO already consumed"); - } else { - self.nullifier = Some(nullifier); - } - - Ok(()) - } - pub fn interpret_asset<'de, ToInterpret: Deserialize<'de>>(&'de self) -> Result { Ok(serde_json::from_slice(&self.asset)?) } @@ -74,11 +62,6 @@ impl UTXO { pub fn log(&self) { info!("UTXO hash is {:?}", hex::encode(self.hash)); info!("UTXO owner is {:?}", hex::encode(self.owner)); - info!( - "UTXO nullifier is {:?}", - self.nullifier.clone().map(|val| hex::encode(val.utxo_hash)) - ); - info!("UTXO asset is {:?}", hex::encode(self.asset.clone())); info!("UTXO amount is {:?}", self.amount); info!("UTXO privacy_flag is {:?}", self.privacy_flag); } @@ -98,14 +81,6 @@ mod tests { AccountId::default() } - fn sample_nullifier() -> UTXONullifier { - UTXONullifier::default() - } - - fn sample_tree_hash() -> TreeHashType { - TreeHashType::default() - } - fn sample_payload() -> UTXOPayload { UTXOPayload { owner: sample_account(), @@ -127,23 +102,6 @@ mod tests { // Ensure hash is created and the UTXO fields are correctly assigned assert_eq!(utxo.owner, payload.owner); assert_eq!(utxo.asset, payload.asset); - assert!(utxo.nullifier.is_none()); - } - - #[test] - fn test_consume_utxo() { - let payload = sample_payload(); - let mut utxo = UTXO::create_utxo_from_payload(payload).unwrap(); - - let nullifier = sample_nullifier(); - - // First consumption should succeed - assert!(utxo.consume_utxo(nullifier.clone()).is_ok()); - assert_eq!(utxo.nullifier, Some(nullifier)); - - // Second consumption should fail - let result = utxo.consume_utxo(sample_nullifier()); - assert!(result.is_err()); } #[test] diff --git a/utxo/src/utxo_tree.rs b/utxo/src/utxo_tree.rs deleted file mode 100644 index 3c0c603..0000000 --- a/utxo/src/utxo_tree.rs +++ /dev/null @@ -1,192 +0,0 @@ -use std::collections::HashMap; - -use common::merkle_tree_public::TreeHashType; -use monotree::database::MemoryDB; -use monotree::hasher::Blake3; -use monotree::{Hasher, Monotree, Proof}; - -use crate::utxo_core::UTXO; - -pub struct UTXOSparseMerkleTree { - pub curr_root: Option, - pub tree: Monotree, - pub hasher: Blake3, - pub store: HashMap, -} - -impl UTXOSparseMerkleTree { - pub fn new() -> Self { - UTXOSparseMerkleTree { - curr_root: None, - tree: Monotree::default(), - hasher: Blake3::new(), - store: HashMap::new(), - } - } - - pub fn insert_item(&mut self, utxo: UTXO) -> Result<(), monotree::Errors> { - let root = self.curr_root.as_ref(); - - let new_root = self.tree.insert(root, &utxo.hash, &utxo.hash)?; - - self.store.insert(utxo.hash, utxo); - - self.curr_root = new_root; - - Ok(()) - } - - pub fn insert_items(&mut self, utxos: Vec) -> Result<(), monotree::Errors> { - let root = self.curr_root.as_ref(); - - let hashes: Vec = utxos.iter().map(|item| item.hash).collect(); - - let new_root = self.tree.inserts(root, &hashes, &hashes)?; - - for utxo in utxos { - self.store.insert(utxo.hash, utxo); - } - - self.curr_root = new_root; - - Ok(()) - } - - pub fn get_item(&mut self, hash: TreeHashType) -> Result, monotree::Errors> { - let hash = self.tree.get(self.curr_root.as_ref(), &hash)?; - - Ok(hash.and_then(|hash| self.store.get(&hash))) - } - - pub fn get_membership_proof( - &mut self, - nullifier_hash: TreeHashType, - ) -> Result, monotree::Errors> { - self.tree - .get_merkle_proof(self.curr_root.as_ref(), &nullifier_hash) - } -} - -impl Default for UTXOSparseMerkleTree { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use common::AccountId; - - use super::*; - use crate::utxo_core::{UTXOPayload, UTXO}; - - fn sample_utxo_payload() -> UTXOPayload { - UTXOPayload { - owner: AccountId::default(), - asset: vec![1, 2, 3], - amount: 10, - privacy_flag: false, - } - } - - fn sample_utxo() -> anyhow::Result { - UTXO::create_utxo_from_payload(sample_utxo_payload()) - } - - #[test] - fn test_utxo_sparse_merkle_tree_new() { - let smt = UTXOSparseMerkleTree::new(); - assert!(smt.curr_root.is_none()); - assert_eq!(smt.store.len(), 0); - } - - #[test] - fn test_insert_item() { - let mut smt = UTXOSparseMerkleTree::new(); - let utxo = sample_utxo().unwrap(); - - let result = smt.insert_item(utxo.clone()); - - // Test insertion is successful - assert!(result.is_ok()); - - // Test UTXO is now stored in the tree - assert_eq!(smt.store.get(&utxo.hash).unwrap().hash, utxo.hash); - - // Test curr_root is updated - assert!(smt.curr_root.is_some()); - } - - #[test] - fn test_insert_items() { - let mut smt = UTXOSparseMerkleTree::new(); - let utxo1 = sample_utxo().unwrap(); - let utxo2 = sample_utxo().unwrap(); - - let result = smt.insert_items(vec![utxo1.clone(), utxo2.clone()]); - - // Test insertion of multiple items is successful - assert!(result.is_ok()); - - // Test UTXOs are now stored in the tree - assert!(smt.store.get(&utxo1.hash).is_some()); - assert!(smt.store.get(&utxo2.hash).is_some()); - - // Test curr_root is updated - assert!(smt.curr_root.is_some()); - } - - #[test] - fn test_get_item_exists() { - let mut smt = UTXOSparseMerkleTree::new(); - let utxo = sample_utxo().unwrap(); - - smt.insert_item(utxo.clone()).unwrap(); - - // Test that the UTXO can be retrieved by hash - let retrieved_utxo = smt.get_item(utxo.hash).unwrap(); - assert!(retrieved_utxo.is_some()); - assert_eq!(retrieved_utxo.unwrap().hash, utxo.hash); - } - - #[test] - fn test_get_item_not_exists() { - let mut smt = UTXOSparseMerkleTree::new(); - let utxo = sample_utxo().unwrap(); - - // Insert one UTXO and try to fetch a different hash - smt.insert_item(utxo).unwrap(); - - let non_existent_hash = TreeHashType::default(); - let result = smt.get_item(non_existent_hash).unwrap(); - - // Test that retrieval for a non-existent UTXO returns None - assert!(result.is_none()); - } - - #[test] - fn test_get_membership_proof() { - let mut smt = UTXOSparseMerkleTree::new(); - let utxo = sample_utxo().unwrap(); - - smt.insert_item(utxo.clone()).unwrap(); - - // Fetch membership proof for the inserted UTXO - let proof = smt.get_membership_proof(utxo.hash).unwrap(); - - // Test proof is generated successfully - assert!(proof.is_some()); - } - - #[test] - fn test_get_membership_proof_not_exists() { - let mut smt = UTXOSparseMerkleTree::new(); - - // Try fetching proof for a non-existent UTXO hash - let non_existent_hash = TreeHashType::default(); - let proof = smt.get_membership_proof(non_existent_hash).unwrap(); - - // Test no proof is generated for a non-existent UTXO - assert!(proof.is_none()); - } -}