openzeppelin_relayer/services/transaction_counter/
mod.rs

1//! This module provides a service for managing transaction counters.
2//!
3//! The `TransactionCounterService` struct offers methods to get, increment,
4//! decrement, and set transaction counts associated with a specific relayer
5//! and address. It uses an in-memory store to keep track of these counts.
6use std::sync::Arc;
7
8use crate::repositories::{TransactionCounterError, TransactionCounterTrait};
9use async_trait::async_trait;
10
11#[cfg(test)]
12use mockall::automock;
13
14#[derive(Clone, Debug)]
15pub struct TransactionCounterService<T> {
16    relayer_id: String,
17    address: String,
18    store: Arc<T>,
19}
20
21impl<T> TransactionCounterService<T> {
22    pub fn new(relayer_id: String, address: String, store: Arc<T>) -> Self {
23        Self {
24            relayer_id,
25            address,
26            store,
27        }
28    }
29}
30
31#[async_trait]
32#[cfg_attr(test, automock)]
33pub trait TransactionCounterServiceTrait: Send + Sync {
34    async fn get(&self) -> Result<Option<u64>, TransactionCounterError>;
35    async fn get_and_increment(&self) -> Result<u64, TransactionCounterError>;
36    async fn decrement(&self) -> Result<u64, TransactionCounterError>;
37    async fn set(&self, value: u64) -> Result<(), TransactionCounterError>;
38}
39
40#[async_trait]
41#[allow(dead_code)]
42impl<T> TransactionCounterServiceTrait for TransactionCounterService<T>
43where
44    T: TransactionCounterTrait + Send + Sync,
45{
46    async fn get(&self) -> Result<Option<u64>, TransactionCounterError> {
47        self.store
48            .get(&self.relayer_id, &self.address)
49            .await
50            .map_err(|e| TransactionCounterError::NotFound(e.to_string()))
51    }
52
53    async fn get_and_increment(&self) -> Result<u64, TransactionCounterError> {
54        self.store
55            .get_and_increment(&self.relayer_id, &self.address)
56            .await
57            .map_err(|e| TransactionCounterError::NotFound(e.to_string()))
58    }
59
60    async fn decrement(&self) -> Result<u64, TransactionCounterError> {
61        self.store
62            .decrement(&self.relayer_id, &self.address)
63            .await
64            .map_err(|e| TransactionCounterError::NotFound(e.to_string()))
65    }
66
67    async fn set(&self, value: u64) -> Result<(), TransactionCounterError> {
68        self.store
69            .set(&self.relayer_id, &self.address, value)
70            .await
71            .map_err(|e| TransactionCounterError::NotFound(e.to_string()))
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use crate::repositories::InMemoryTransactionCounter;
79
80    #[tokio::test]
81    async fn test_transaction_counter() {
82        let store = Arc::new(InMemoryTransactionCounter::default());
83        let service =
84            TransactionCounterService::new("relayer_id".to_string(), "address".to_string(), store);
85
86        assert_eq!(service.get().await.unwrap(), None);
87        assert_eq!(service.get_and_increment().await.unwrap(), 0);
88        assert_eq!(service.get_and_increment().await.unwrap(), 1);
89        assert_eq!(service.decrement().await.unwrap(), 1);
90        assert!(service.set(10).await.is_ok());
91        assert_eq!(service.get().await.unwrap(), Some(10));
92    }
93}