lssa/utxo/src/utxo_core.rs

163 lines
4.6 KiB
Rust
Raw Normal View History

2024-10-22 12:46:44 +03:00
use anyhow::Result;
2025-05-16 20:54:11 -03:00
use common::{merkle_tree_public::TreeHashType, AccountId};
use log::info;
2025-05-16 21:55:25 -03:00
use rand::{rngs::OsRng, RngCore};
2024-10-22 12:46:44 +03:00
use serde::{Deserialize, Serialize};
use sha2::{digest::FixedOutput, Digest};
///Raw asset data
pub type Asset = Vec<u8>;
2025-05-16 21:55:25 -03:00
pub type Randomness = [u8; 32];
2024-10-22 12:46:44 +03:00
2024-12-02 00:55:11 +01:00
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
2024-10-22 12:46:44 +03:00
///Container for raw utxo payload
pub struct UTXO {
pub hash: TreeHashType,
pub owner: AccountId,
pub asset: Asset,
2024-12-02 00:55:11 +01:00
// TODO: change to u256
pub amount: u128,
pub privacy_flag: bool,
2025-05-16 21:55:25 -03:00
pub randomness: Randomness,
2024-10-22 12:46:44 +03:00
}
2024-12-20 11:02:12 +02:00
#[derive(Debug, Clone, Serialize, Deserialize)]
2024-10-22 12:46:44 +03:00
pub struct UTXOPayload {
pub owner: AccountId,
pub asset: Asset,
2024-12-02 00:55:11 +01:00
// TODO: change to u256
pub amount: u128,
pub privacy_flag: bool,
2025-05-16 21:55:25 -03:00
pub randomness: Randomness,
2024-10-22 12:46:44 +03:00
}
2025-05-16 21:55:25 -03:00
impl UTXOPayload {
fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
result.extend_from_slice(&self.owner);
result.extend_from_slice(&self.asset);
result.extend_from_slice(&self.amount.to_be_bytes());
result.push(self.privacy_flag as u8);
result.extend_from_slice(&self.randomness);
result
}
}
2024-10-22 12:46:44 +03:00
2025-05-16 21:55:25 -03:00
impl UTXO {
pub fn new(owner: AccountId, asset: Asset, amount: u128, privacy_flag: bool) -> Self {
let mut randomness = Randomness::default();
OsRng.fill_bytes(&mut randomness);
let payload = UTXOPayload {
owner,
asset,
amount,
privacy_flag,
randomness,
};
Self::create_utxo_from_payload(payload)
}
pub fn create_utxo_from_payload(payload_with_asset: UTXOPayload) -> Self {
2024-10-22 12:46:44 +03:00
let mut hasher = sha2::Sha256::new();
2025-07-21 18:46:50 -03:00
hasher.update(payload_with_asset.to_bytes());
2024-10-22 12:46:44 +03:00
let hash = <TreeHashType>::from(hasher.finalize_fixed());
2025-05-16 21:55:25 -03:00
Self {
2024-10-22 12:46:44 +03:00
hash,
owner: payload_with_asset.owner,
asset: payload_with_asset.asset,
2024-12-02 00:55:11 +01:00
amount: payload_with_asset.amount,
privacy_flag: payload_with_asset.privacy_flag,
2025-05-16 21:55:25 -03:00
randomness: payload_with_asset.randomness,
}
2024-10-22 12:46:44 +03:00
}
pub fn interpret_asset<'de, ToInterpret: Deserialize<'de>>(&'de self) -> Result<ToInterpret> {
Ok(serde_json::from_slice(&self.asset)?)
}
2024-12-30 07:43:27 +02:00
pub fn into_payload(&self) -> UTXOPayload {
2024-12-30 09:10:04 +02:00
UTXOPayload {
owner: self.owner,
asset: self.asset.clone(),
amount: self.amount,
privacy_flag: self.privacy_flag,
2025-05-16 21:55:25 -03:00
randomness: self.randomness,
2024-12-30 07:43:27 +02:00
}
}
pub fn log(&self) {
info!("UTXO hash is {:?}", hex::encode(self.hash));
2025-01-03 08:13:59 +02:00
info!("UTXO owner is {:?}", hex::encode(self.owner));
info!("UTXO asset is {:?}", hex::encode(self.asset.clone()));
info!("UTXO amount is {:?}", self.amount);
info!("UTXO privacy_flag is {:?}", self.privacy_flag);
}
2024-10-22 12:46:44 +03:00
}
2024-10-25 00:36:10 +02:00
#[cfg(test)]
mod tests {
use super::*;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct TestAsset {
id: u32,
name: String,
}
fn sample_account() -> AccountId {
AccountId::default()
}
fn sample_payload() -> UTXOPayload {
UTXOPayload {
owner: sample_account(),
2024-10-25 00:53:06 +02:00
asset: serde_json::to_vec(&TestAsset {
id: 1,
name: "Test".to_string(),
})
.unwrap(),
2024-12-02 00:55:11 +01:00
amount: 10,
privacy_flag: false,
2025-05-16 21:55:25 -03:00
randomness: Randomness::default(),
2024-10-25 00:36:10 +02:00
}
}
2024-10-25 00:36:36 +02:00
#[test]
fn test_create_utxo_from_payload() {
let payload = sample_payload();
2025-05-16 21:55:25 -03:00
let utxo = UTXO::create_utxo_from_payload(payload.clone());
2024-10-25 00:36:36 +02:00
// Ensure hash is created and the UTXO fields are correctly assigned
assert_eq!(utxo.owner, payload.owner);
assert_eq!(utxo.asset, payload.asset);
2024-10-25 00:36:49 +02:00
}
2024-10-25 00:36:10 +02:00
2024-10-25 00:37:02 +02:00
#[test]
fn test_interpret_asset() {
let payload = sample_payload();
2025-05-16 21:55:25 -03:00
let utxo = UTXO::create_utxo_from_payload(payload);
2024-10-25 00:37:02 +02:00
// Interpret asset as TestAsset
let interpreted: TestAsset = utxo.interpret_asset().unwrap();
2024-10-25 00:53:06 +02:00
assert_eq!(
interpreted,
TestAsset {
id: 1,
name: "Test".to_string()
}
);
2024-10-25 00:37:02 +02:00
}
2024-10-25 00:37:11 +02:00
#[test]
fn test_interpret_invalid_asset() {
let mut payload = sample_payload();
payload.asset = vec![0, 1, 2, 3]; // Invalid data for deserialization
2025-05-16 21:55:25 -03:00
let utxo = UTXO::create_utxo_from_payload(payload);
2024-10-25 00:37:02 +02:00
2024-10-25 00:37:11 +02:00
// This should fail because the asset is not valid JSON for TestAsset
let result: Result<TestAsset> = utxo.interpret_asset();
assert!(result.is_err());
}
2024-10-25 00:36:10 +02:00
}