clawdentity_core/runtime/
trusted_receipts.rs1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4use crate::db::now_utc_ms;
5
6#[derive(Clone, Default)]
7pub struct TrustedReceiptsStore {
8 inner: Arc<Mutex<HashMap<String, i64>>>,
9}
10
11impl TrustedReceiptsStore {
12 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn mark_trusted(&self, frame_id: impl Into<String>) {
19 let frame_id = frame_id.into();
20 if frame_id.trim().is_empty() {
21 return;
22 }
23 if let Ok(mut guard) = self.inner.lock() {
24 guard.insert(frame_id, now_utc_ms());
25 }
26 }
27
28 pub fn is_trusted(&self, frame_id: &str) -> bool {
30 if frame_id.trim().is_empty() {
31 return false;
32 }
33 match self.inner.lock() {
34 Ok(guard) => guard.contains_key(frame_id),
35 Err(_) => false,
36 }
37 }
38
39 pub fn purge_before(&self, cutoff_ms: i64) -> usize {
41 let Ok(mut guard) = self.inner.lock() else {
42 return 0;
43 };
44
45 let initial_len = guard.len();
46 guard.retain(|_, marked_at_ms| *marked_at_ms >= cutoff_ms);
47 initial_len.saturating_sub(guard.len())
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::TrustedReceiptsStore;
54
55 #[test]
56 fn marks_checks_and_purges_receipts() {
57 let store = TrustedReceiptsStore::new();
58 store.mark_trusted("frame-1");
59 assert!(store.is_trusted("frame-1"));
60 let purged = store.purge_before(i64::MAX);
61 assert_eq!(purged, 1);
62 assert!(!store.is_trusted("frame-1"));
63 }
64}