From 837cc31a9305ad15e4245a05c32473ef6a0846e3 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 7 May 2025 16:34:52 -0300 Subject: [PATCH 1/8] use x coordinate as key for aes --- .../key_management/ephemeral_key_holder.rs | 11 ++---- accounts/src/key_management/mod.rs | 34 ++++++------------- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/accounts/src/key_management/ephemeral_key_holder.rs b/accounts/src/key_management/ephemeral_key_holder.rs index 9e3a9b1..266cfa3 100644 --- a/accounts/src/key_management/ephemeral_key_holder.rs +++ b/accounts/src/key_management/ephemeral_key_holder.rs @@ -3,6 +3,7 @@ use elliptic_curve::PrimeField; use k256::{AffinePoint, FieldBytes, Scalar}; use log::info; use rand::{rngs::OsRng, RngCore}; +use elliptic_curve::point::AffineCoordinates; use super::constants_types::{CipherText, Nonce}; @@ -39,14 +40,8 @@ impl EphemeralKeyHolder { viewing_public_key_receiver: AffinePoint, data: &[u8], ) -> (CipherText, Nonce) { - let key_point = self.calculate_shared_secret_sender(viewing_public_key_receiver); - let binding = serde_json::to_vec(&key_point).unwrap(); - let key_raw = &binding.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw.try_into().unwrap(); - - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); + let shared_secret = self.calculate_shared_secret_sender(viewing_public_key_receiver); + let cipher = Aes256Gcm::new(&shared_secret.x()); let nonce = Aes256Gcm::generate_nonce(&mut OsRng); (cipher.encrypt(&nonce, data).unwrap(), nonce) diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 25673f6..79418ec 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -5,6 +5,7 @@ use ephemeral_key_holder::EphemeralKeyHolder; use k256::AffinePoint; use log::info; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; +use elliptic_curve::point::AffineCoordinates; use crate::account_core::PublicKey; @@ -63,14 +64,8 @@ impl AddressKeyHolder { ciphertext: CipherText, nonce: Nonce, ) -> Result, aes_gcm::Error> { - let key_point = self.calculate_shared_secret_receiver(ephemeral_public_key_sender); - let binding = serde_json::to_vec(&key_point).unwrap(); - let key_raw = &binding.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw.try_into().unwrap(); - - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); + let shared_secret = self.calculate_shared_secret_receiver(ephemeral_public_key_sender); + let cipher = Aes256Gcm::new(&shared_secret.x()); cipher.decrypt(&nonce, ciphertext.as_slice()) } @@ -107,18 +102,22 @@ impl AddressKeyHolder { #[cfg(test)] mod tests { + use std::io::Read; + use aes_gcm::{ aead::{Aead, KeyInit, OsRng}, Aes256Gcm, }; use constants_types::{CipherText, Nonce}; use constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST}; - use elliptic_curve::ff::Field; + use elliptic_curve::{ff::Field, PrimeField}; use elliptic_curve::group::prime::PrimeCurveAffine; use k256::{AffinePoint, ProjectivePoint, Scalar}; + use elliptic_curve::point::AffineCoordinates; use super::*; + #[test] fn test_new_os_random() { // Ensure that a new AddressKeyHolder instance can be created without errors. @@ -154,22 +153,14 @@ mod tests { let address_key_holder = AddressKeyHolder::new_os_random(); // Generate an ephemeral key and shared secret - let scalar = Scalar::random(OsRng); let ephemeral_public_key_sender = address_key_holder .produce_ephemeral_key_holder() .generate_ephemeral_public_key(); let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); - // Prepare the encryption key from shared secret - let key_raw = serde_json::to_vec(&shared_secret).unwrap(); - let key_raw_adjust_pre = &key_raw.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap(); - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); - // Encrypt sample data + let cipher = Aes256Gcm::new(&shared_secret.x()); let nonce = Nonce::from_slice(b"unique nonce"); let plaintext = b"Sensitive data"; let ciphertext = cipher @@ -315,12 +306,7 @@ mod tests { let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); - // Prepare the encryption key from shared secret - let key_raw = serde_json::to_vec(&shared_secret).unwrap(); - let key_raw_adjust_pre = &key_raw.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap(); - let key: Key = key_raw_adjust.into(); - let cipher = Aes256Gcm::new(&key); + let cipher = Aes256Gcm::new(&shared_secret.x()); let ciphertext = cipher .encrypt(nonce, plaintext.as_ref()) From 7a117150efaab1d3fed7277dc4d4b721b0a2e81a Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 7 May 2025 16:36:30 -0300 Subject: [PATCH 2/8] remove usage of deprecated function --- accounts/src/key_management/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 79418ec..712e8a4 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -138,7 +138,7 @@ mod tests { // Generate a random ephemeral public key sender let scalar = Scalar::random(&mut OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); // Calculate shared secret let shared_secret = @@ -216,7 +216,7 @@ mod tests { // Generate ephemeral public key and shared secret let scalar = Scalar::random(OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); @@ -256,7 +256,7 @@ mod tests { // Generate ephemeral public key and shared secret let scalar = Scalar::random(OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); @@ -298,7 +298,7 @@ mod tests { // Generate ephemeral key and shared secret let scalar = Scalar::random(OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); // Encrypt sample data let plaintext = b"Round-trip test data"; From 7572188ab08040dc06ed8b271b0139b91296e9f1 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 7 May 2025 16:37:03 -0300 Subject: [PATCH 3/8] fmt --- accounts/src/key_management/ephemeral_key_holder.rs | 2 +- accounts/src/key_management/mod.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/accounts/src/key_management/ephemeral_key_holder.rs b/accounts/src/key_management/ephemeral_key_holder.rs index 266cfa3..6210369 100644 --- a/accounts/src/key_management/ephemeral_key_holder.rs +++ b/accounts/src/key_management/ephemeral_key_holder.rs @@ -1,9 +1,9 @@ use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit}; +use elliptic_curve::point::AffineCoordinates; use elliptic_curve::PrimeField; use k256::{AffinePoint, FieldBytes, Scalar}; use log::info; use rand::{rngs::OsRng, RngCore}; -use elliptic_curve::point::AffineCoordinates; use super::constants_types::{CipherText, Nonce}; diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 712e8a4..1e690ac 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -1,11 +1,11 @@ use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit}; use common::merkle_tree_public::TreeHashType; use constants_types::{CipherText, Nonce}; +use elliptic_curve::point::AffineCoordinates; use ephemeral_key_holder::EphemeralKeyHolder; use k256::AffinePoint; use log::info; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; -use elliptic_curve::point::AffineCoordinates; use crate::account_core::PublicKey; @@ -110,14 +110,13 @@ mod tests { }; use constants_types::{CipherText, Nonce}; use constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST}; - use elliptic_curve::{ff::Field, PrimeField}; use elliptic_curve::group::prime::PrimeCurveAffine; - use k256::{AffinePoint, ProjectivePoint, Scalar}; use elliptic_curve::point::AffineCoordinates; + use elliptic_curve::{ff::Field, PrimeField}; + use k256::{AffinePoint, ProjectivePoint, Scalar}; use super::*; - #[test] fn test_new_os_random() { // Ensure that a new AddressKeyHolder instance can be created without errors. From 74d8fd54d9e794b22c69f62df3196ecf0cec2da2 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 7 May 2025 16:52:08 -0300 Subject: [PATCH 4/8] fix tests --- .../key_management/ephemeral_key_holder.rs | 2 +- accounts/src/key_management/mod.rs | 26 ++++--------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/accounts/src/key_management/ephemeral_key_holder.rs b/accounts/src/key_management/ephemeral_key_holder.rs index 6210369..ecfb09e 100644 --- a/accounts/src/key_management/ephemeral_key_holder.rs +++ b/accounts/src/key_management/ephemeral_key_holder.rs @@ -1,4 +1,4 @@ -use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit}; +use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, KeyInit}; use elliptic_curve::point::AffineCoordinates; use elliptic_curve::PrimeField; use k256::{AffinePoint, FieldBytes, Scalar}; diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 1e690ac..474bd99 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -1,4 +1,4 @@ -use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit}; +use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit}; use common::merkle_tree_public::TreeHashType; use constants_types::{CipherText, Nonce}; use elliptic_curve::point::AffineCoordinates; @@ -102,17 +102,15 @@ impl AddressKeyHolder { #[cfg(test)] mod tests { - use std::io::Read; - use aes_gcm::{ aead::{Aead, KeyInit, OsRng}, Aes256Gcm, }; use constants_types::{CipherText, Nonce}; use constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST}; + use elliptic_curve::ff::Field; use elliptic_curve::group::prime::PrimeCurveAffine; use elliptic_curve::point::AffineCoordinates; - use elliptic_curve::{ff::Field, PrimeField}; use k256::{AffinePoint, ProjectivePoint, Scalar}; use super::*; @@ -137,7 +135,7 @@ mod tests { // Generate a random ephemeral public key sender let scalar = Scalar::random(&mut OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); // Calculate shared secret let shared_secret = @@ -219,15 +217,8 @@ mod tests { let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); - // Prepare the encryption key from shared secret - let key_raw = serde_json::to_vec(&shared_secret).unwrap(); - let key_raw_adjust_pre = &key_raw.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap(); - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); - // Encrypt sample data with a specific nonce + let cipher = Aes256Gcm::new(&shared_secret.x()); let nonce = Nonce::from_slice(b"unique nonce"); let plaintext = b"Sensitive data"; let ciphertext = cipher @@ -259,15 +250,8 @@ mod tests { let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); - // Prepare the encryption key from shared secret - let key_raw = serde_json::to_vec(&shared_secret).unwrap(); - let key_raw_adjust_pre = &key_raw.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap(); - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); - // Encrypt sample data + let cipher = Aes256Gcm::new(&shared_secret.x()); let nonce = Nonce::from_slice(b"unique nonce"); let plaintext = b"Sensitive data"; let ciphertext = cipher From f50ef5be9af65e055dc4df728d78fd33b571a6df Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 19:59:51 -0300 Subject: [PATCH 5/8] wip --- accounts/src/account_core/mod.rs | 31 +++-- node_core/src/chain_storage/mod.rs | 2 +- node_core/src/lib.rs | 14 +-- node_rpc/src/process.rs | 8 +- utxo/src/lib.rs | 1 - utxo/src/utxo_tree.rs | 192 ----------------------------- 6 files changed, 30 insertions(+), 218 deletions(-) delete mode 100644 utxo/src/utxo_tree.rs diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 2d3417c..6498597 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, hash::Hash}; use anyhow::Result; use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transaction::Tag}; @@ -7,7 +7,6 @@ use log::info; use serde::Serialize; use utxo::{ utxo_core::{UTXOPayload, UTXO}, - utxo_tree::UTXOSparseMerkleTree, }; use crate::key_management::{ @@ -23,7 +22,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 +41,26 @@ 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 new_with_balance(balance: u64) -> Self { let key_holder = AddressKeyHolder::new_os_random(); let address = key_holder.address; - let utxo_tree = UTXOSparseMerkleTree::new(); + let utxos = HashMap::new(); Self { key_holder, address, balance, - utxo_tree, + utxos, } } @@ -92,7 +91,7 @@ impl Account { utxo_nullifier_map: HashMap, ) -> Result<()> { for (hash, nullifier) in utxo_nullifier_map { - if let Some(utxo_entry) = self.utxo_tree.store.get_mut(&hash) { + if let Some(utxo_entry) = self.utxos.get_mut(&hash) { utxo_entry.consume_utxo(nullifier)?; } } @@ -101,7 +100,13 @@ impl Account { } 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) { @@ -123,7 +128,7 @@ impl Account { let asset_utxo = UTXO::create_utxo_from_payload(payload_with_asset)?; - self.utxo_tree.insert_item(asset_utxo)?; + self.utxos.insert(asset_utxo.hash, asset_utxo); Ok(()) } @@ -193,7 +198,7 @@ mod tests { let result = account.mark_spent_utxo(utxo_nullifier_map); assert!(result.is_ok()); - assert!(account.utxo_tree.store.get(&account.address).is_none()); + assert!(account.utxos.get(&account.address).is_none()); } #[test] @@ -205,7 +210,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.store.len(), 2); } #[test] @@ -225,6 +230,6 @@ mod tests { let result = account.add_asset(asset, amount, false); assert!(result.is_ok()); - assert_eq!(account.utxo_tree.store.len(), 1); + assert_eq!(account.utxos.store.len(), 1); } } diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index f8bcf4e..cfa80b0 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_item(utxo)?; } } } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index c0a97e5..4442112 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -1062,7 +1062,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); - acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone() + acc.utxos.get_item(new_utxo_hash)?.unwrap().clone() }; new_utxo.log(); @@ -1102,7 +1102,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); let new_utxo = acc - .utxo_tree + .utxos .get_item(new_utxo_hash) .unwrap() .unwrap() @@ -1238,7 +1238,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); acc.log(); - acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone() + acc.utxos.get_item(new_utxo_hash)?.unwrap().clone() }; new_utxo.log(); info!( @@ -1278,7 +1278,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); acc.log(); - acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone() + acc.utxos.get_item(new_utxo_hash)?.unwrap().clone() }; new_utxo.log(); info!( @@ -1323,7 +1323,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); acc.log(); - let new_utxo = acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone(); + let new_utxo = acc.utxos.get_item(new_utxo_hash)?.unwrap().clone(); new_utxo.log(); info!( @@ -1343,7 +1343,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); acc.log(); - let new_utxo = acc.utxo_tree.get_item(new_utxo_hash)?.unwrap().clone(); + let new_utxo = acc.utxos.get_item(new_utxo_hash)?.unwrap().clone(); new_utxo.log(); info!( @@ -1557,7 +1557,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); let new_utxo = acc - .utxo_tree + .utxos .get_item(new_utxo_hash) .unwrap() .unwrap() diff --git a/node_rpc/src/process.rs b/node_rpc/src/process.rs index 38621ba..59837ad 100644 --- a/node_rpc/src/process.rs +++ b/node_rpc/src/process.rs @@ -268,7 +268,7 @@ impl JsonHandler { .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; let utxo = acc - .utxo_tree + .utxos .get_item(utxo_hash) .map_err(|err| { RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) @@ -512,7 +512,7 @@ impl JsonHandler { .get_mut(&acc_addr_sender) .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; - acc.utxo_tree + acc.utxos .get_item(utxo_hash) .map_err(|err| { RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) @@ -647,7 +647,7 @@ impl JsonHandler { .get_mut(&acc_addr_sender) .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; - acc.utxo_tree + acc.utxos .get_item(utxo_hash) .map_err(|err| { RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) @@ -735,7 +735,7 @@ impl JsonHandler { .get_mut(&acc_addr_sender) .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; - acc.utxo_tree + acc.utxos .get_item(utxo_hash) .map_err(|err| { RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) 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_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()); - } -} From c6a4a00fdaa90dc1f9e1760ab5372a8944126d0d Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 20:25:23 -0300 Subject: [PATCH 6/8] remove utxo tree --- accounts/src/account_core/mod.rs | 5 ++--- node_core/src/chain_storage/mod.rs | 2 +- node_core/src/lib.rs | 16 +++++++--------- node_rpc/src/process.rs | 20 ++++---------------- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 6498597..0c7bbdd 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -198,7 +198,6 @@ mod tests { let result = account.mark_spent_utxo(utxo_nullifier_map); assert!(result.is_ok()); - assert!(account.utxos.get(&account.address).is_none()); } #[test] @@ -210,7 +209,7 @@ mod tests { let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]); assert!(result.is_ok()); - assert_eq!(account.utxos.store.len(), 2); + assert_eq!(account.utxos.len(), 2); } #[test] @@ -230,6 +229,6 @@ mod tests { let result = account.add_asset(asset, amount, false); assert!(result.is_ok()); - assert_eq!(account.utxos.store.len(), 1); + assert_eq!(account.utxos.len(), 1); } } diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index cfa80b0..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.utxos.insert_item(utxo)?; + acc.utxos.insert(utxo.hash, utxo); } } } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 4442112..25be979 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -1062,7 +1062,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); - acc.utxos.get_item(new_utxo_hash)?.unwrap().clone() + acc.utxos.get(&new_utxo_hash).unwrap().clone() }; new_utxo.log(); @@ -1103,8 +1103,7 @@ impl NodeCore { let new_utxo = acc .utxos - .get_item(new_utxo_hash) - .unwrap() + .get(&new_utxo_hash) .unwrap() .clone(); @@ -1238,7 +1237,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); acc.log(); - acc.utxos.get_item(new_utxo_hash)?.unwrap().clone() + acc.utxos.get(&new_utxo_hash).unwrap().clone() }; new_utxo.log(); info!( @@ -1278,7 +1277,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); acc.log(); - acc.utxos.get_item(new_utxo_hash)?.unwrap().clone() + acc.utxos.get(&new_utxo_hash).unwrap().clone() }; new_utxo.log(); info!( @@ -1323,7 +1322,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); acc.log(); - let new_utxo = acc.utxos.get_item(new_utxo_hash)?.unwrap().clone(); + let new_utxo = acc.utxos.get(&new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( @@ -1343,7 +1342,7 @@ impl NodeCore { let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); acc.log(); - let new_utxo = acc.utxos.get_item(new_utxo_hash)?.unwrap().clone(); + let new_utxo = acc.utxos.get(&new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( @@ -1558,8 +1557,7 @@ impl NodeCore { let new_utxo = acc .utxos - .get_item(new_utxo_hash) - .unwrap() + .get(&new_utxo_hash) .unwrap() .clone(); new_utxo.log(); diff --git a/node_rpc/src/process.rs b/node_rpc/src/process.rs index 59837ad..f4937e9 100644 --- a/node_rpc/src/process.rs +++ b/node_rpc/src/process.rs @@ -269,10 +269,7 @@ impl JsonHandler { let utxo = acc .utxos - .get_item(utxo_hash) - .map_err(|err| { - RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) - })? + .get(&utxo_hash) .ok_or(RpcError::new_internal_error( None, "UTXO does not exist in the tree", @@ -513,10 +510,7 @@ impl JsonHandler { .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; acc.utxos - .get_item(utxo_hash) - .map_err(|err| { - RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) - })? + .get(&utxo_hash) .ok_or(RpcError::new_internal_error( None, "UTXO does not exist in tree", @@ -648,10 +642,7 @@ impl JsonHandler { .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; acc.utxos - .get_item(utxo_hash) - .map_err(|err| { - RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) - })? + .get(&utxo_hash) .ok_or(RpcError::new_internal_error( None, "UTXO does not exist in tree", @@ -736,10 +727,7 @@ impl JsonHandler { .ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?; acc.utxos - .get_item(utxo_hash) - .map_err(|err| { - RpcError::new_internal_error(None, &format!("DB fetch failure {err:?}")) - })? + .get(&utxo_hash) .ok_or(RpcError::new_internal_error( None, "UTXO does not exist in tree", From 6aa6c9d34ffc3c58f44264d8ee3c187ba442204c Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 22:06:06 -0300 Subject: [PATCH 7/8] fmt --- accounts/src/account_core/mod.rs | 4 +--- node_core/src/lib.rs | 12 ++---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 0c7bbdd..38d9e9c 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -5,9 +5,7 @@ use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transac use k256::AffinePoint; use log::info; use serde::Serialize; -use utxo::{ - utxo_core::{UTXOPayload, UTXO}, -}; +use utxo::utxo_core::{UTXOPayload, UTXO}; use crate::key_management::{ constants_types::{CipherText, Nonce}, diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 25be979..5228e9b 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -1101,11 +1101,7 @@ impl NodeCore { .map(|new_utxo_hash| { let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); - let new_utxo = acc - .utxos - .get(&new_utxo_hash) - .unwrap() - .clone(); + let new_utxo = acc.utxos.get(&new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( @@ -1555,11 +1551,7 @@ impl NodeCore { .map(|(acc_addr_rec, new_utxo_hash)| { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); - let new_utxo = acc - .utxos - .get(&new_utxo_hash) - .unwrap() - .clone(); + let new_utxo = acc.utxos.get(&new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( From b6700f8adb01f8bb2361c197fa9aee2e3a41983f Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 22:21:43 -0300 Subject: [PATCH 8/8] fmt --- accounts/src/account_core/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 38d9e9c..d5f5e90 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, hash::Hash}; +use std::collections::HashMap; use anyhow::Result; use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transaction::Tag};