1use super::transaction::UserTransactionData;
3use crate::error::UserStateError;
4use ic_cdk::export::{candid::CandidType, serde::Deserialize};
5
6#[derive(Debug, CandidType, Deserialize, Clone, PartialEq)]
7pub struct UserChainData {
8 pub nonce: u64,
9 pub transactions: Vec<UserTransactionData>,
10}
11
12impl UserChainData {
13 pub fn default() -> Self {
15 UserChainData {
16 nonce: 0,
17 transactions: vec![],
18 }
19 }
20
21 pub fn new(transaction: UserTransactionData) -> Self {
22 UserChainData {
23 nonce: 0,
24 transactions: vec![transaction],
25 }
26 }
27
28 pub fn add(&mut self, nonce: u64, transaction: UserTransactionData) {
30 self.nonce = nonce;
31 self.transactions.push(transaction);
32 }
33
34 pub fn remove(&mut self, index: usize) -> Result<&UserTransactionData, UserStateError> {
38 if index >= self.transactions.len() {
39 return Err(UserStateError::TransactionNotFound);
40 }
41
42 self.transactions.remove(index);
43
44 self.get_transaction(index)
45 }
46
47 pub fn get_transaction(&self, index: usize) -> Result<&UserTransactionData, UserStateError> {
49 self.transactions
50 .get(index)
51 .ok_or(UserStateError::TransactionNotFound)
52 }
53
54 pub fn get_transactions(&self) -> &Vec<UserTransactionData> {
55 &self.transactions
56 }
57
58 pub fn add_transaction(
61 &mut self,
62 nonce: u64,
63 transaction: UserTransactionData,
64 ) -> Result<&UserTransactionData, UserStateError> {
65 self.add(nonce, transaction);
66
67 self.get_transaction(self.transactions.len() - 1)
68 }
69
70 pub fn clear_transactions(&mut self) {
73 self.transactions.clear();
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use proptest::prelude::*;
81
82 proptest! {
83 #[test]
84 fn test_add_transaction(nonce: u64, transaction: UserTransactionData) {
85 let mut chain_data = UserChainData::default();
86
87 chain_data.add(nonce, transaction.clone());
88
89 assert_eq!(chain_data.nonce, nonce);
90 assert_eq!(chain_data.transactions, vec![transaction]);
91 }
92
93 #[test]
94 fn test_clear_transactions(transaction: Vec<UserTransactionData>) {
95 let mut chain_data = UserChainData::default();
96
97 chain_data.transactions = transaction.clone();
98
99 chain_data.clear_transactions();
100
101 assert_eq!(chain_data.nonce, 0);
102
103 assert_eq!(chain_data.transactions, vec![]);
104 }
105
106 #[test]
107 fn test_get_transaction(transaction: Vec<UserTransactionData>) {
108 let mut chain_data = UserChainData::default();
109
110 chain_data.transactions = transaction.clone();
111
112 for i in 0..chain_data.transactions.len() {
113 assert_eq!(chain_data.get_transaction(i).unwrap(), &transaction[i]);
114 }
115 }
116
117 #[test]
118 fn test_get_transactions(transaction: Vec<UserTransactionData>) {
119 let mut chain_data = UserChainData::default();
120
121 chain_data.transactions = transaction.clone();
122
123 assert_eq!(chain_data.get_transactions(), &transaction);
124 }
125
126 #[test]
127 fn test_add_transaction_error(transaction: Vec<UserTransactionData>) {
128 let mut chain_data = UserChainData::default();
129
130 chain_data.transactions = transaction.clone();
131
132 let result = chain_data.get_transaction(chain_data.transactions.len());
133
134 match result {
135 Err(UserStateError::TransactionNotFound) => (),
136 _ => panic!("Expected TransactionNotFound error"),
137 }
138 }
139
140 #[test]
141 fn test_add_transaction_to_chain(nonce: u64, transaction: UserTransactionData) {
142 let mut chain_data = UserChainData::default();
143
144 chain_data.add_transaction(nonce, transaction.clone()).unwrap();
145
146 assert_eq!(chain_data.nonce, nonce);
147 assert_eq!(chain_data.transactions, vec![transaction]);
148 }
149
150 #[test]
151 fn test_add_transaction_to_chain_error(nonce: u64, transaction: UserTransactionData) {
152 let mut chain_data = UserChainData::default();
153
154 chain_data.add_transaction(nonce, transaction.clone()).unwrap();
155
156 let result = chain_data.get_transaction(chain_data.transactions.len());
157
158 match result {
159 Err(UserStateError::TransactionNotFound) => (),
160 _ => panic!("Expected TransactionNotFound error"),
161 }
162 }
163
164 #[test]
165 fn test_clear_transactions_error(transaction: Vec<UserTransactionData>) {
166 let mut chain_data = UserChainData::default();
167
168 chain_data.transactions = transaction.clone();
169
170 chain_data.clear_transactions();
171
172 let result = chain_data.get_transaction(chain_data.transactions.len());
173
174 match result {
175 Err(UserStateError::TransactionNotFound) => (),
176 _ => panic!("Expected TransactionNotFound error"),
177 }
178 }
179 }
180}