1use serde::{Deserialize, Serialize};
8use std::collections::{HashMap, HashSet};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ClientChannelFunding {
19 pub params_json: String,
21 pub funding_proofs_json: String,
23 pub channel_secret_hex: String,
25 pub keyset_info_json: String,
27 pub sender_pubkey_hex: String,
29 pub capacity: u64,
31 pub funding_token_amount: u64,
33 pub mint_url: String,
35 pub created_at: u64,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ClientPaymentState {
44 pub balance: u64,
46 pub signature: String,
48 pub payment_count: u64,
50 pub last_payment_at: u64,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
56pub enum ClientChannelState {
57 #[default]
59 Open,
60 Closed,
62}
63
64pub trait ClientStorage {
73 fn save_funding(&mut self, channel_id: &str, funding: ClientChannelFunding);
77
78 fn get_funding(&self, channel_id: &str) -> Option<&ClientChannelFunding>;
80
81 fn get_payment_state(&self, channel_id: &str) -> Option<&ClientPaymentState>;
85
86 fn save_payment_state(&mut self, channel_id: &str, state: ClientPaymentState);
88
89 fn get_state(&self, channel_id: &str) -> ClientChannelState;
93
94 fn set_closed(&mut self, channel_id: &str);
96
97 fn list_channel_ids(&self) -> Vec<String>;
101
102 fn delete(&mut self, channel_id: &str);
104}
105
106#[derive(Debug, Default)]
115pub struct MemoryClientStorage {
116 funding: HashMap<String, ClientChannelFunding>,
117 payments: HashMap<String, ClientPaymentState>,
118 closed: HashSet<String>,
119}
120
121impl MemoryClientStorage {
122 pub fn new() -> Self {
124 Self::default()
125 }
126
127 pub fn channel_count(&self) -> usize {
129 self.funding.len()
130 }
131}
132
133impl ClientStorage for MemoryClientStorage {
134 fn save_funding(&mut self, channel_id: &str, funding: ClientChannelFunding) {
135 self.funding.insert(channel_id.to_string(), funding);
136 }
137
138 fn get_funding(&self, channel_id: &str) -> Option<&ClientChannelFunding> {
139 self.funding.get(channel_id)
140 }
141
142 fn get_payment_state(&self, channel_id: &str) -> Option<&ClientPaymentState> {
143 self.payments.get(channel_id)
144 }
145
146 fn save_payment_state(&mut self, channel_id: &str, state: ClientPaymentState) {
147 self.payments.insert(channel_id.to_string(), state);
148 }
149
150 fn get_state(&self, channel_id: &str) -> ClientChannelState {
151 if self.closed.contains(channel_id) {
152 ClientChannelState::Closed
153 } else if self.funding.contains_key(channel_id) {
154 ClientChannelState::Open
155 } else {
156 ClientChannelState::Closed
158 }
159 }
160
161 fn set_closed(&mut self, channel_id: &str) {
162 self.closed.insert(channel_id.to_string());
163 }
164
165 fn list_channel_ids(&self) -> Vec<String> {
166 self.funding.keys().cloned().collect()
167 }
168
169 fn delete(&mut self, channel_id: &str) {
170 self.funding.remove(channel_id);
171 self.payments.remove(channel_id);
172 self.closed.remove(channel_id);
173 }
174}
175
176#[cfg(test)]
181mod tests {
182 use super::*;
183
184 fn make_test_funding() -> ClientChannelFunding {
185 ClientChannelFunding {
186 params_json: r#"{"test": true}"#.to_string(),
187 funding_proofs_json: "[]".to_string(),
188 channel_secret_hex: "aa".repeat(32),
189 keyset_info_json: "{}".to_string(),
190 sender_pubkey_hex: "02".to_string() + &"bb".repeat(32),
191 capacity: 1000,
192 funding_token_amount: 1100,
193 mint_url: "https://mint.example.com".to_string(),
194 created_at: 1234567890,
195 }
196 }
197
198 fn make_test_payment_state(balance: u64) -> ClientPaymentState {
199 ClientPaymentState {
200 balance,
201 signature: "sig".to_string(),
202 payment_count: 1,
203 last_payment_at: 1234567890,
204 }
205 }
206
207 #[test]
208 fn test_memory_storage_funding() {
209 let mut storage = MemoryClientStorage::new();
210 let channel_id = "test_channel_1";
211
212 assert!(storage.get_funding(channel_id).is_none());
214 assert_eq!(storage.channel_count(), 0);
215
216 storage.save_funding(channel_id, make_test_funding());
218
219 let funding = storage.get_funding(channel_id).unwrap();
221 assert_eq!(funding.capacity, 1000);
222 assert_eq!(storage.channel_count(), 1);
223
224 assert_eq!(storage.get_state(channel_id), ClientChannelState::Open);
226 }
227
228 #[test]
229 fn test_memory_storage_payments() {
230 let mut storage = MemoryClientStorage::new();
231 let channel_id = "test_channel_1";
232
233 storage.save_funding(channel_id, make_test_funding());
234
235 assert!(storage.get_payment_state(channel_id).is_none());
237
238 storage.save_payment_state(channel_id, make_test_payment_state(100));
240
241 let state = storage.get_payment_state(channel_id).unwrap();
242 assert_eq!(state.balance, 100);
243 assert_eq!(state.payment_count, 1);
244
245 storage.save_payment_state(channel_id, make_test_payment_state(200));
247
248 let state = storage.get_payment_state(channel_id).unwrap();
249 assert_eq!(state.balance, 200);
250 }
251
252 #[test]
253 fn test_memory_storage_lifecycle() {
254 let mut storage = MemoryClientStorage::new();
255 let channel_id = "test_channel_1";
256
257 assert_eq!(storage.get_state(channel_id), ClientChannelState::Closed);
259
260 storage.save_funding(channel_id, make_test_funding());
262 assert_eq!(storage.get_state(channel_id), ClientChannelState::Open);
263
264 storage.set_closed(channel_id);
266 assert_eq!(storage.get_state(channel_id), ClientChannelState::Closed);
267 }
268
269 #[test]
270 fn test_memory_storage_delete() {
271 let mut storage = MemoryClientStorage::new();
272 let channel_id = "test_channel_1";
273
274 storage.save_funding(channel_id, make_test_funding());
275 storage.save_payment_state(channel_id, make_test_payment_state(100));
276 storage.set_closed(channel_id);
277
278 assert_eq!(storage.channel_count(), 1);
279
280 storage.delete(channel_id);
282
283 assert_eq!(storage.channel_count(), 0);
284 assert!(storage.get_funding(channel_id).is_none());
285 assert!(storage.get_payment_state(channel_id).is_none());
286 assert_eq!(storage.get_state(channel_id), ClientChannelState::Closed);
287 }
288
289 #[test]
290 fn test_memory_storage_list() {
291 let mut storage = MemoryClientStorage::new();
292
293 storage.save_funding("channel_1", make_test_funding());
294 storage.save_funding("channel_2", make_test_funding());
295 storage.save_funding("channel_3", make_test_funding());
296
297 let mut ids = storage.list_channel_ids();
298 ids.sort();
299
300 assert_eq!(ids, vec!["channel_1", "channel_2", "channel_3"]);
301 }
302}