openzeppelin_relayer/utils/
transaction.rs

1use crate::constants::DEFAULT_TRANSACTION_SPEED;
2use crate::models::evm::Speed;
3use crate::utils::time::minutes_ms;
4
5/// Gets the resubmit timeout for a given speed
6/// Returns the timeout in milliseconds based on the speed:
7/// - SafeLow: 10 minutes
8/// - Average: 5 minutes
9/// - Fast: 3 minutes
10/// - Fastest: 2 minutes
11///   If no speed is provided, uses the default transaction speed
12pub fn get_resubmit_timeout_for_speed(speed: &Option<Speed>) -> i64 {
13    let speed_value = speed.clone().unwrap_or(DEFAULT_TRANSACTION_SPEED);
14
15    match speed_value {
16        Speed::SafeLow => minutes_ms(10),
17        Speed::Average => minutes_ms(5),
18        Speed::Fast => minutes_ms(3),
19        Speed::Fastest => minutes_ms(2),
20    }
21}
22
23/// Calculates the resubmit age with exponential backoff
24///
25/// # Arguments
26/// * `timeout` - The base timeout in milliseconds
27/// * `attempts` - The number of attempts made so far
28///
29/// # Returns
30/// The new timeout with exponential backoff applied: timeout * 2^(attempts-1)
31pub fn get_resubmit_timeout_with_backoff(timeout: i64, attempts: usize) -> i64 {
32    if attempts <= 1 {
33        timeout
34    } else {
35        timeout * 2_i64.pow((attempts - 1) as u32)
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn test_get_resubmit_timeout_for_speed() {
45        // Test with existing speeds
46        assert_eq!(
47            get_resubmit_timeout_for_speed(&Some(Speed::SafeLow)),
48            minutes_ms(10)
49        );
50        assert_eq!(
51            get_resubmit_timeout_for_speed(&Some(Speed::Average)),
52            minutes_ms(5)
53        );
54        assert_eq!(
55            get_resubmit_timeout_for_speed(&Some(Speed::Fast)),
56            minutes_ms(3)
57        );
58        assert_eq!(
59            get_resubmit_timeout_for_speed(&Some(Speed::Fastest)),
60            minutes_ms(2)
61        );
62
63        // Test with None speed (should return default)
64        assert_eq!(
65            get_resubmit_timeout_for_speed(&None),
66            minutes_ms(3) // DEFAULT_TRANSACTION_SPEED is Speed::Fast
67        );
68    }
69
70    #[test]
71    fn test_get_resubmit_timeout_with_backoff() {
72        let base_timeout = 300000; // 5 minutes in ms
73
74        // First attempt - no backoff
75        assert_eq!(get_resubmit_timeout_with_backoff(base_timeout, 1), 300000);
76
77        // Second attempt - 2x backoff
78        assert_eq!(get_resubmit_timeout_with_backoff(base_timeout, 2), 600000);
79
80        // Third attempt - 4x backoff
81        assert_eq!(get_resubmit_timeout_with_backoff(base_timeout, 3), 1200000);
82
83        // Fourth attempt - 8x backoff
84        assert_eq!(get_resubmit_timeout_with_backoff(base_timeout, 4), 2400000);
85
86        // Edge case - attempt 0 should be treated as attempt 1
87        assert_eq!(get_resubmit_timeout_with_backoff(base_timeout, 0), 300000);
88    }
89}