b3_users/data/
transaction.rs

1#[cfg(test)]
2use crate::mocks::ic_timestamp;
3
4#[cfg(not(test))]
5use ic_cdk::api::time as ic_timestamp;
6
7use ic_cdk::export::{candid::CandidType, serde::Deserialize};
8
9#[derive(CandidType, Debug, Deserialize, Clone, PartialEq)]
10pub struct UserTransactionData {
11    pub data: Vec<u8>,
12    pub cycle: u64,
13    pub timestamp: u64,
14}
15
16impl UserTransactionData {
17    /// Creates a default TransactionData with empty data and a timestamp of 0.
18    pub fn default() -> Self {
19        UserTransactionData {
20            cycle: 0,
21            data: vec![],
22            timestamp: 0,
23        }
24    }
25
26    /// Creates a new TransactionData with the given data and timestamp.
27    pub fn new(data: Vec<u8>, cycle: u64, timestamp: u64) -> Self {
28        UserTransactionData {
29            data,
30            cycle,
31            timestamp,
32        }
33    }
34
35    /// Creates a new TransactionData with the given data and the current timestamp.
36    pub fn new_with_current_time(data: Vec<u8>, cycle: u64) -> Self {
37        let timestamp = ic_timestamp();
38
39        UserTransactionData {
40            data,
41            cycle,
42            timestamp,
43        }
44    }
45
46    /// Computes the hash of the transaction by concatenating the data and the timestamp.
47    pub fn get_hash(&self) -> Vec<u8> {
48        let mut hash = vec![];
49        hash.extend_from_slice(&self.data);
50        hash.extend_from_slice(&self.timestamp.to_be_bytes());
51
52        hash
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use proptest::prelude::*;
60
61    proptest! {
62        #[test]
63        fn test_transaction_hash(data: Vec<u8>,cycle: u64, timestamp: u64) {
64            let transaction = UserTransactionData::new(data.clone(), cycle, timestamp);
65            let hash = transaction.get_hash();
66
67            assert_eq!(hash.len(), data.len() + 8);
68            assert_eq!(&hash[0..data.len()], data.as_slice());
69            assert_eq!(&hash[data.len()..], &timestamp.to_be_bytes());
70        }
71
72        #[test]
73        fn test_transaction_hash_with_current_time(data: Vec<u8>, cycle: u64) {
74            let transaction = UserTransactionData::new_with_current_time(data.clone(), cycle);
75            let hash = transaction.get_hash();
76
77            assert_eq!(hash.len(), data.len() + 8);
78            assert_eq!(&hash[0..data.len()], data.as_slice());
79            assert_eq!(&hash[data.len()..], &transaction.timestamp.to_be_bytes());
80        }
81    }
82}