rustywallet_vanity/
result.rs

1//! Result types for vanity address generation.
2
3use crate::pattern::Pattern;
4use rustywallet_keys::prelude::*;
5use std::time::Duration;
6
7/// Result of a successful vanity address search.
8#[derive(Debug, Clone)]
9pub struct VanityResult {
10    /// The private key that generates the vanity address.
11    pub private_key: PrivateKey,
12    /// The public key derived from the private key.
13    pub public_key: PublicKey,
14    /// The vanity address that matched the pattern.
15    pub address: String,
16    /// The pattern that was matched.
17    pub matched_pattern: Pattern,
18    /// Statistics about the search.
19    pub stats: SearchStats,
20}
21
22impl VanityResult {
23    /// Create a new vanity result.
24    pub fn new(
25        private_key: PrivateKey,
26        address: String,
27        matched_pattern: Pattern,
28        stats: SearchStats,
29    ) -> Self {
30        let public_key = private_key.public_key();
31        Self {
32            private_key,
33            public_key,
34            address,
35            matched_pattern,
36            stats,
37        }
38    }
39}
40
41/// Statistics about a vanity search.
42#[derive(Debug, Clone)]
43pub struct SearchStats {
44    /// Number of keys checked.
45    pub attempts: u64,
46    /// Time elapsed during search.
47    pub elapsed: Duration,
48    /// Keys checked per second.
49    pub rate: f64,
50}
51
52impl SearchStats {
53    /// Create new search stats.
54    pub fn new(attempts: u64, elapsed: Duration) -> Self {
55        let rate = if elapsed.as_secs_f64() > 0.0 {
56            attempts as f64 / elapsed.as_secs_f64()
57        } else {
58            0.0
59        };
60
61        Self {
62            attempts,
63            elapsed,
64            rate,
65        }
66    }
67}
68
69/// Progress information during a search.
70#[derive(Debug, Clone)]
71pub struct SearchProgress {
72    /// Number of keys checked so far.
73    pub attempts: u64,
74    /// Time elapsed so far.
75    pub elapsed: Duration,
76    /// Current rate (keys/sec).
77    pub rate: f64,
78    /// Estimated time remaining (if calculable).
79    pub estimated_remaining: Option<Duration>,
80}
81
82impl SearchProgress {
83    /// Create new progress info.
84    pub fn new(attempts: u64, elapsed: Duration, expected_attempts: Option<u64>) -> Self {
85        let rate = if elapsed.as_secs_f64() > 0.0 {
86            attempts as f64 / elapsed.as_secs_f64()
87        } else {
88            0.0
89        };
90
91        let estimated_remaining = expected_attempts.and_then(|expected| {
92            if rate > 0.0 && attempts < expected {
93                let remaining_attempts = expected - attempts;
94                Some(Duration::from_secs_f64(remaining_attempts as f64 / rate))
95            } else {
96                None
97            }
98        });
99
100        Self {
101            attempts,
102            elapsed,
103            rate,
104            estimated_remaining,
105        }
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn test_search_stats() {
115        let stats = SearchStats::new(1000, Duration::from_secs(1));
116        assert_eq!(stats.attempts, 1000);
117        assert!((stats.rate - 1000.0).abs() < 0.1);
118    }
119
120    #[test]
121    fn test_search_progress() {
122        let progress = SearchProgress::new(500, Duration::from_secs(1), Some(1000));
123        assert_eq!(progress.attempts, 500);
124        assert!(progress.estimated_remaining.is_some());
125    }
126}