qudag_protocol/
state.rs

1//! Protocol state machine implementation.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::time::{Duration, Instant, SystemTime};
6use thiserror::Error;
7use tracing::{debug, error, warn};
8use uuid::Uuid;
9
10use crate::message::{HandshakeType, Message, MessageType, ProtocolVersion};
11
12/// Errors that can occur during state operations.
13#[derive(Debug, Error)]
14pub enum StateError {
15    /// Invalid state transition
16    #[error("Invalid state transition from {from:?} to {to:?}")]
17    InvalidTransition {
18        from: ProtocolState,
19        to: ProtocolState,
20    },
21
22    /// State synchronization failed
23    #[error("State synchronization failed: {reason}")]
24    SyncFailed { reason: String },
25
26    /// Invalid state data
27    #[error("Invalid state data: {reason}")]
28    InvalidData { reason: String },
29
30    /// State operation timeout
31    #[error("State operation timed out after {timeout:?}")]
32    Timeout { timeout: Duration },
33
34    /// Session not found
35    #[error("Session not found: {session_id}")]
36    SessionNotFound { session_id: Uuid },
37
38    /// Protocol version mismatch
39    #[error("Protocol version mismatch: expected {expected:?}, got {actual:?}")]
40    VersionMismatch {
41        expected: ProtocolVersion,
42        actual: ProtocolVersion,
43    },
44}
45
46/// Protocol state enumeration with detailed substates
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
48pub enum ProtocolState {
49    /// Initial state - node starting up
50    #[default]
51    Initial,
52
53    /// Handshake states
54    Handshake(HandshakeState),
55
56    /// Active protocol states
57    Active(ActiveState),
58
59    /// Synchronization states
60    Synchronizing(SyncState),
61
62    /// Error states
63    Error(ErrorState),
64
65    /// Shutting down
66    Shutdown,
67}
68
69/// Handshake state substates
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub enum HandshakeState {
72    /// Waiting for handshake initiation
73    Waiting,
74    /// Handshake in progress - sent init, waiting for response
75    InProgress,
76    /// Received handshake response, processing
77    Processing,
78    /// Handshake completed successfully
79    Completed,
80    /// Handshake failed
81    Failed,
82}
83
84/// Active protocol substates
85#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
86pub enum ActiveState {
87    /// Normal operation - processing messages
88    Normal,
89    /// High load - prioritizing critical messages
90    HighLoad,
91    /// Degraded - some components not functioning optimally
92    Degraded,
93}
94
95/// Synchronization substates
96#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
97pub enum SyncState {
98    /// Requesting state from peers
99    Requesting,
100    /// Receiving state data
101    Receiving,
102    /// Applying received state
103    Applying,
104    /// Verifying synchronized state
105    Verifying,
106}
107
108/// Error state types
109#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110pub enum ErrorState {
111    /// Network connectivity issues
112    NetworkError,
113    /// Consensus failure
114    ConsensusError,
115    /// Cryptographic error
116    CryptoError,
117    /// Resource exhaustion
118    ResourceError,
119    /// Internal protocol error
120    InternalError,
121}
122
123/// Session information for tracking peer connections
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct SessionInfo {
126    /// Session identifier
127    pub id: Uuid,
128    /// Peer identifier
129    pub peer_id: Vec<u8>,
130    /// Protocol version negotiated
131    pub protocol_version: ProtocolVersion,
132    /// Session state
133    pub state: ProtocolState,
134    /// Session start time
135    pub started_at: SystemTime,
136    /// Last activity timestamp
137    pub last_activity: SystemTime,
138    /// Session capabilities
139    pub capabilities: Vec<String>,
140    /// Session metrics
141    pub metrics: SessionMetrics,
142}
143
144/// Session performance metrics
145#[derive(Debug, Clone, Default, Serialize, Deserialize)]
146pub struct SessionMetrics {
147    /// Messages sent
148    pub messages_sent: u64,
149    /// Messages received
150    pub messages_received: u64,
151    /// Bytes sent
152    pub bytes_sent: u64,
153    /// Bytes received
154    pub bytes_received: u64,
155    /// Average response time
156    pub avg_response_time: Duration,
157    /// Error count
158    pub error_count: u64,
159}
160
161/// Protocol state manager
162#[derive(Debug)]
163pub struct ProtocolStateMachine {
164    /// Current protocol state
165    current_state: ProtocolState,
166    /// Previous state for rollback
167    previous_state: Option<ProtocolState>,
168    /// State transition history
169    state_history: Vec<StateTransition>,
170    /// Active sessions
171    sessions: HashMap<Uuid, SessionInfo>,
172    /// State machine start time
173    started_at: Instant,
174    /// Protocol version
175    protocol_version: ProtocolVersion,
176    /// State machine configuration
177    config: StateMachineConfig,
178}
179
180/// State transition record
181#[derive(Debug, Clone)]
182pub struct StateTransition {
183    /// Timestamp of transition
184    pub timestamp: Instant,
185    /// Previous state
186    pub from: ProtocolState,
187    /// New state
188    pub to: ProtocolState,
189    /// Reason for transition
190    pub reason: String,
191    /// Duration in previous state
192    pub duration: Duration,
193}
194
195/// State machine configuration
196#[derive(Debug, Clone)]
197pub struct StateMachineConfig {
198    /// Maximum number of concurrent sessions
199    pub max_sessions: usize,
200    /// Session timeout duration
201    pub session_timeout: Duration,
202    /// Handshake timeout duration
203    pub handshake_timeout: Duration,
204    /// Sync timeout duration
205    pub sync_timeout: Duration,
206    /// Maximum state history size
207    pub max_history_size: usize,
208}
209
210impl Default for StateMachineConfig {
211    fn default() -> Self {
212        Self {
213            max_sessions: 1000,
214            session_timeout: Duration::from_secs(300), // 5 minutes
215            handshake_timeout: Duration::from_secs(30), // 30 seconds
216            sync_timeout: Duration::from_secs(60),     // 1 minute
217            max_history_size: 1000,
218        }
219    }
220}
221
222impl ProtocolStateMachine {
223    /// Create a new protocol state machine
224    pub fn new(protocol_version: ProtocolVersion) -> Self {
225        Self {
226            current_state: ProtocolState::Initial,
227            previous_state: None,
228            state_history: Vec::new(),
229            sessions: HashMap::new(),
230            started_at: Instant::now(),
231            protocol_version,
232            config: StateMachineConfig::default(),
233        }
234    }
235
236    /// Create with custom configuration
237    pub fn with_config(protocol_version: ProtocolVersion, config: StateMachineConfig) -> Self {
238        Self {
239            current_state: ProtocolState::Initial,
240            previous_state: None,
241            state_history: Vec::new(),
242            sessions: HashMap::new(),
243            started_at: Instant::now(),
244            protocol_version,
245            config,
246        }
247    }
248
249    /// Get current state
250    pub fn current_state(&self) -> &ProtocolState {
251        &self.current_state
252    }
253
254    /// Get active sessions count
255    pub fn active_sessions(&self) -> usize {
256        self.sessions.len()
257    }
258
259    /// Get protocol version
260    pub fn protocol_version(&self) -> &ProtocolVersion {
261        &self.protocol_version
262    }
263
264    /// Get state machine uptime
265    pub fn uptime(&self) -> Duration {
266        self.started_at.elapsed()
267    }
268
269    /// Transition to a new state
270    pub fn transition_to(
271        &mut self,
272        new_state: ProtocolState,
273        reason: String,
274    ) -> Result<(), StateError> {
275        // Validate transition
276        if !self.is_valid_transition(&self.current_state, &new_state) {
277            return Err(StateError::InvalidTransition {
278                from: self.current_state.clone(),
279                to: new_state,
280            });
281        }
282
283        let now = Instant::now();
284        let duration = if let Some(last_transition) = self.state_history.last() {
285            now.duration_since(last_transition.timestamp)
286        } else {
287            now.duration_since(self.started_at)
288        };
289
290        // Record state transition
291        let transition = StateTransition {
292            timestamp: now,
293            from: self.current_state.clone(),
294            to: new_state.clone(),
295            reason: reason.clone(),
296            duration,
297        };
298
299        debug!(
300            "State transition: {:?} -> {:?} ({})",
301            self.current_state, new_state, reason
302        );
303
304        // Update states
305        self.previous_state = Some(self.current_state.clone());
306        self.current_state = new_state;
307
308        // Add to history
309        self.state_history.push(transition);
310
311        // Limit history size
312        if self.state_history.len() > self.config.max_history_size {
313            self.state_history.remove(0);
314        }
315
316        // Perform state entry actions
317        self.on_state_entry(&reason)?;
318
319        Ok(())
320    }
321
322    /// Check if a state transition is valid
323    fn is_valid_transition(&self, from: &ProtocolState, to: &ProtocolState) -> bool {
324        use ActiveState::*;
325        use ErrorState::*;
326        use HandshakeState::*;
327        use ProtocolState::*;
328        use SyncState::*;
329
330        match (from, to) {
331            // From Initial
332            (Initial, Handshake(Waiting)) => true,
333            (Initial, Error(_)) => true,
334            (Initial, Shutdown) => true,
335
336            // From Handshake states
337            (Handshake(Waiting), Handshake(InProgress)) => true,
338            (Handshake(InProgress), Handshake(Processing)) => true,
339            (Handshake(InProgress), Handshake(Failed)) => true,
340            (Handshake(Processing), Handshake(Completed)) => true,
341            (Handshake(Processing), Handshake(Failed)) => true,
342            (Handshake(Completed), Active(Normal)) => true,
343            (Handshake(Failed), Error(NetworkError)) => true,
344            (Handshake(_), Shutdown) => true,
345
346            // From Active states
347            (Active(Normal), Active(HighLoad)) => true,
348            (Active(Normal), Active(Degraded)) => true,
349            (Active(Normal), Synchronizing(Requesting)) => true,
350            (Active(HighLoad), Active(Normal)) => true,
351            (Active(HighLoad), Active(Degraded)) => true,
352            (Active(Degraded), Active(Normal)) => true,
353            (Active(Degraded), Synchronizing(Requesting)) => true,
354            (Active(_), Error(_)) => true,
355            (Active(_), Shutdown) => true,
356
357            // From Synchronizing states
358            (Synchronizing(Requesting), Synchronizing(Receiving)) => true,
359            (Synchronizing(Requesting), Error(NetworkError)) => true,
360            (Synchronizing(Receiving), Synchronizing(Applying)) => true,
361            (Synchronizing(Receiving), Error(NetworkError)) => true,
362            (Synchronizing(Applying), Synchronizing(Verifying)) => true,
363            (Synchronizing(Applying), Error(InternalError)) => true,
364            (Synchronizing(Verifying), Active(Normal)) => true,
365            (Synchronizing(Verifying), Error(InternalError)) => true,
366            (Synchronizing(_), Shutdown) => true,
367
368            // From Error states
369            (Error(_), Initial) => true, // Recovery
370            (Error(_), Shutdown) => true,
371
372            // From Shutdown
373            (Shutdown, _) => false, // No transitions from shutdown
374
375            // Same state (for updates)
376            (a, b) if a == b => true,
377
378            _ => false,
379        }
380    }
381
382    /// Perform actions when entering a new state
383    fn on_state_entry(&mut self, reason: &str) -> Result<(), StateError> {
384        let current_state = self.current_state.clone();
385        match &current_state {
386            ProtocolState::Initial => {
387                debug!("Entered Initial state: {}", reason);
388                // Clean up any existing sessions
389                self.sessions.clear();
390            }
391
392            ProtocolState::Handshake(handshake_state) => {
393                debug!("Entered Handshake state {:?}: {}", handshake_state, reason);
394                match handshake_state {
395                    HandshakeState::InProgress => {
396                        // Start handshake timeout
397                        // TODO: Implement timeout mechanism
398                    }
399                    HandshakeState::Failed => {
400                        warn!("Handshake failed: {}", reason);
401                        // Clean up failed handshake sessions
402                        self.cleanup_failed_sessions();
403                    }
404                    _ => {}
405                }
406            }
407
408            ProtocolState::Active(active_state) => {
409                debug!("Entered Active state {:?}: {}", active_state, reason);
410                match active_state {
411                    ActiveState::HighLoad => {
412                        // Implement load shedding
413                        warn!("Entering high load state, implementing load shedding");
414                    }
415                    ActiveState::Degraded => {
416                        warn!("Entering degraded state: {}", reason);
417                    }
418                    _ => {}
419                }
420            }
421
422            ProtocolState::Synchronizing(sync_state) => {
423                debug!("Entered Synchronizing state {:?}: {}", sync_state, reason);
424            }
425
426            ProtocolState::Error(error_state) => {
427                error!("Entered Error state {:?}: {}", error_state, reason);
428                // Implement error recovery procedures
429                self.handle_error_state(error_state, reason)?;
430            }
431
432            ProtocolState::Shutdown => {
433                debug!("Entered Shutdown state: {}", reason);
434                // Begin graceful shutdown
435                self.begin_shutdown();
436            }
437        }
438
439        Ok(())
440    }
441
442    /// Handle error state entry
443    fn handle_error_state(
444        &mut self,
445        error_state: &ErrorState,
446        reason: &str,
447    ) -> Result<(), StateError> {
448        match error_state {
449            ErrorState::NetworkError => {
450                // Close problematic connections
451                self.cleanup_failed_sessions();
452            }
453            ErrorState::ConsensusError => {
454                // Request state synchronization
455                // TODO: Trigger sync process
456            }
457            ErrorState::CryptoError => {
458                // Critical error - may need to restart
459                error!("Critical cryptographic error: {}", reason);
460            }
461            ErrorState::ResourceError => {
462                // Implement resource cleanup
463                self.cleanup_resources();
464            }
465            ErrorState::InternalError => {
466                // Log detailed error information
467                error!("Internal protocol error: {}", reason);
468            }
469        }
470        Ok(())
471    }
472
473    /// Begin graceful shutdown
474    fn begin_shutdown(&mut self) {
475        debug!("Beginning graceful shutdown");
476
477        // Close all active sessions
478        for (session_id, session) in &mut self.sessions {
479            debug!("Closing session: {}", session_id);
480            session.state = ProtocolState::Shutdown;
481        }
482
483        // TODO: Send disconnect messages to peers
484        // TODO: Flush pending operations
485    }
486
487    /// Clean up failed sessions
488    fn cleanup_failed_sessions(&mut self) {
489        let failed_sessions: Vec<Uuid> = self
490            .sessions
491            .iter()
492            .filter(|(_, session)| {
493                matches!(
494                    session.state,
495                    ProtocolState::Error(_) | ProtocolState::Handshake(HandshakeState::Failed)
496                )
497            })
498            .map(|(id, _)| *id)
499            .collect();
500
501        for session_id in failed_sessions {
502            debug!("Cleaning up failed session: {}", session_id);
503            self.sessions.remove(&session_id);
504        }
505    }
506
507    /// Clean up resources
508    fn cleanup_resources(&mut self) {
509        debug!("Cleaning up resources");
510
511        // Remove old state history
512        if self.state_history.len() > self.config.max_history_size / 2 {
513            let keep_from = self.state_history.len() - self.config.max_history_size / 2;
514            self.state_history.drain(0..keep_from);
515        }
516
517        // Remove timed out sessions
518        self.cleanup_timed_out_sessions();
519    }
520
521    /// Clean up timed out sessions
522    fn cleanup_timed_out_sessions(&mut self) {
523        let now = SystemTime::now();
524        let timeout = self.config.session_timeout;
525
526        let timed_out_sessions: Vec<Uuid> = self
527            .sessions
528            .iter()
529            .filter(|(_, session)| {
530                now.duration_since(session.last_activity)
531                    .unwrap_or(Duration::ZERO)
532                    > timeout
533            })
534            .map(|(id, _)| *id)
535            .collect();
536
537        for session_id in timed_out_sessions {
538            debug!("Removing timed out session: {}", session_id);
539            self.sessions.remove(&session_id);
540        }
541    }
542
543    /// Create a new session
544    pub fn create_session(
545        &mut self,
546        peer_id: Vec<u8>,
547        protocol_version: ProtocolVersion,
548        capabilities: Vec<String>,
549    ) -> Result<Uuid, StateError> {
550        // Check session limit
551        if self.sessions.len() >= self.config.max_sessions {
552            return Err(StateError::InvalidData {
553                reason: "Maximum number of sessions reached".to_string(),
554            });
555        }
556
557        // Verify protocol version compatibility
558        if !self.protocol_version.is_compatible(&protocol_version) {
559            return Err(StateError::VersionMismatch {
560                expected: self.protocol_version.clone(),
561                actual: protocol_version,
562            });
563        }
564
565        let session_id = Uuid::new_v4();
566        let now = SystemTime::now();
567
568        let session = SessionInfo {
569            id: session_id,
570            peer_id,
571            protocol_version,
572            state: ProtocolState::Handshake(HandshakeState::Waiting),
573            started_at: now,
574            last_activity: now,
575            capabilities,
576            metrics: SessionMetrics::default(),
577        };
578
579        self.sessions.insert(session_id, session);
580
581        debug!("Created new session: {}", session_id);
582        Ok(session_id)
583    }
584
585    /// Update session state
586    pub fn update_session_state(
587        &mut self,
588        session_id: Uuid,
589        new_state: ProtocolState,
590    ) -> Result<(), StateError> {
591        // First get the current session state for validation
592        let current_session_state = self
593            .sessions
594            .get(&session_id)
595            .ok_or(StateError::SessionNotFound { session_id })?
596            .state
597            .clone();
598
599        // Validate session state transition
600        if !self.is_valid_transition(&current_session_state, &new_state) {
601            return Err(StateError::InvalidTransition {
602                from: current_session_state,
603                to: new_state,
604            });
605        }
606
607        // Now get mutable reference and update
608        let session = self
609            .sessions
610            .get_mut(&session_id)
611            .ok_or(StateError::SessionNotFound { session_id })?;
612        session.state = new_state;
613        session.last_activity = SystemTime::now();
614
615        Ok(())
616    }
617
618    /// Get session information
619    pub fn get_session(&self, session_id: &Uuid) -> Option<&SessionInfo> {
620        self.sessions.get(session_id)
621    }
622
623    /// Remove a session
624    pub fn remove_session(&mut self, session_id: &Uuid) -> Option<SessionInfo> {
625        self.sessions.remove(session_id)
626    }
627
628    /// Process a protocol message and update state accordingly
629    pub fn process_message(
630        &mut self,
631        message: &Message,
632        session_id: Option<Uuid>,
633    ) -> Result<(), StateError> {
634        // Update last activity for session if provided
635        if let Some(session_id) = session_id {
636            if let Some(session) = self.sessions.get_mut(&session_id) {
637                session.last_activity = SystemTime::now();
638                session.metrics.messages_received += 1;
639                session.metrics.bytes_received += message.payload.len() as u64;
640            }
641        }
642
643        // Process message based on type and current state
644        match &message.msg_type {
645            MessageType::Handshake(handshake_type) => {
646                self.process_handshake_message(handshake_type, message, session_id)?;
647            }
648            MessageType::Control(_) => {
649                // Control messages can be processed in most states
650                if !matches!(self.current_state, ProtocolState::Shutdown) {
651                    // Process control message
652                    debug!(
653                        "Processing control message in state {:?}",
654                        self.current_state
655                    );
656                }
657            }
658            _ => {
659                // Other messages require active state
660                match &self.current_state {
661                    ProtocolState::Active(_) => {
662                        // Process message in active state
663                        debug!("Processing message in active state");
664                    }
665                    _ => {
666                        warn!(
667                            "Received message in non-active state: {:?}",
668                            self.current_state
669                        );
670                    }
671                }
672            }
673        }
674
675        Ok(())
676    }
677
678    /// Process handshake messages
679    fn process_handshake_message(
680        &mut self,
681        handshake_type: &HandshakeType,
682        _message: &Message,
683        session_id: Option<Uuid>,
684    ) -> Result<(), StateError> {
685        match handshake_type {
686            HandshakeType::Init => {
687                if matches!(
688                    self.current_state,
689                    ProtocolState::Initial | ProtocolState::Handshake(_)
690                ) {
691                    self.transition_to(
692                        ProtocolState::Handshake(HandshakeState::InProgress),
693                        "Received handshake init".to_string(),
694                    )?;
695                }
696            }
697            HandshakeType::Response => {
698                if matches!(
699                    self.current_state,
700                    ProtocolState::Handshake(HandshakeState::InProgress)
701                ) {
702                    self.transition_to(
703                        ProtocolState::Handshake(HandshakeState::Processing),
704                        "Received handshake response".to_string(),
705                    )?;
706                }
707            }
708            HandshakeType::Complete => {
709                if matches!(
710                    self.current_state,
711                    ProtocolState::Handshake(HandshakeState::Processing)
712                ) {
713                    self.transition_to(
714                        ProtocolState::Handshake(HandshakeState::Completed),
715                        "Handshake completed".to_string(),
716                    )?;
717
718                    // Transition to active state
719                    self.transition_to(
720                        ProtocolState::Active(ActiveState::Normal),
721                        "Handshake successful, entering active state".to_string(),
722                    )?;
723                }
724            }
725            HandshakeType::VersionNegotiation => {
726                // Handle version negotiation
727                debug!("Processing version negotiation");
728            }
729        }
730
731        // Update session state if provided
732        if let Some(session_id) = session_id {
733            if let Some(session) = self.sessions.get_mut(&session_id) {
734                session.state = self.current_state.clone();
735            }
736        }
737
738        Ok(())
739    }
740
741    /// Get state transition history
742    pub fn get_state_history(&self) -> &[StateTransition] {
743        &self.state_history
744    }
745
746    /// Get all active sessions
747    pub fn get_sessions(&self) -> &HashMap<Uuid, SessionInfo> {
748        &self.sessions
749    }
750
751    /// Check if the state machine is in a healthy state
752    pub fn is_healthy(&self) -> bool {
753        !matches!(
754            self.current_state,
755            ProtocolState::Error(_) | ProtocolState::Shutdown
756        )
757    }
758
759    /// Get state machine metrics
760    pub fn get_metrics(&self) -> StateMachineMetrics {
761        let mut total_messages_sent = 0;
762        let mut total_messages_received = 0;
763        let mut total_bytes_sent = 0;
764        let mut total_bytes_received = 0;
765        let mut total_errors = 0;
766
767        for session in self.sessions.values() {
768            total_messages_sent += session.metrics.messages_sent;
769            total_messages_received += session.metrics.messages_received;
770            total_bytes_sent += session.metrics.bytes_sent;
771            total_bytes_received += session.metrics.bytes_received;
772            total_errors += session.metrics.error_count;
773        }
774
775        StateMachineMetrics {
776            current_state: self.current_state.clone(),
777            uptime: self.uptime(),
778            active_sessions: self.sessions.len(),
779            total_state_transitions: self.state_history.len(),
780            total_messages_sent,
781            total_messages_received,
782            total_bytes_sent,
783            total_bytes_received,
784            total_errors,
785        }
786    }
787}
788
789/// State machine performance metrics
790#[derive(Debug, Clone, Serialize, Deserialize, Default)]
791pub struct StateMachineMetrics {
792    /// Current protocol state
793    pub current_state: ProtocolState,
794    /// State machine uptime
795    pub uptime: Duration,
796    /// Number of active sessions
797    pub active_sessions: usize,
798    /// Total state transitions
799    pub total_state_transitions: usize,
800    /// Total messages sent across all sessions
801    pub total_messages_sent: u64,
802    /// Total messages received across all sessions
803    pub total_messages_received: u64,
804    /// Total bytes sent
805    pub total_bytes_sent: u64,
806    /// Total bytes received
807    pub total_bytes_received: u64,
808    /// Total errors
809    pub total_errors: u64,
810}
811
812/// State management trait defining the interface for state operations.
813pub trait StateManager {
814    /// Initialize protocol state.
815    fn init() -> Result<ProtocolStateMachine, StateError>;
816
817    /// Transition to a new state.
818    fn transition(&mut self, new_state: ProtocolState) -> Result<(), StateError>;
819
820    /// Get current state.
821    fn get_state(&self) -> &ProtocolState;
822
823    /// Validate state transition.
824    fn validate_transition(&self, new_state: &ProtocolState) -> bool;
825}
826
827impl StateManager for ProtocolStateMachine {
828    fn init() -> Result<ProtocolStateMachine, StateError> {
829        Ok(ProtocolStateMachine::new(ProtocolVersion::CURRENT))
830    }
831
832    fn transition(&mut self, new_state: ProtocolState) -> Result<(), StateError> {
833        self.transition_to(new_state, "Manual transition".to_string())
834    }
835
836    fn get_state(&self) -> &ProtocolState {
837        &self.current_state
838    }
839
840    fn validate_transition(&self, new_state: &ProtocolState) -> bool {
841        self.is_valid_transition(&self.current_state, new_state)
842    }
843}