qudag_protocol/
compatibility.rs

1//! Backward compatibility layer for QuDAG protocol.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use thiserror::Error;
6
7use crate::message::{Message, MessageType, ProtocolVersion};
8use crate::versioning::{VersionError, VersionManager};
9
10/// Compatibility layer errors
11#[derive(Debug, Error)]
12pub enum CompatibilityError {
13    /// Version not supported
14    #[error("Version not supported: {version:?}")]
15    VersionNotSupported { version: ProtocolVersion },
16
17    /// Feature not available in target version
18    #[error("Feature '{feature}' not available in version {version:?}")]
19    FeatureNotAvailable {
20        feature: String,
21        version: ProtocolVersion,
22    },
23
24    /// Message transformation failed
25    #[error("Message transformation failed: {reason}")]
26    TransformationFailed { reason: String },
27
28    /// Incompatible message format
29    #[error("Incompatible message format for version {version:?}")]
30    IncompatibleFormat { version: ProtocolVersion },
31
32    /// Version error
33    #[error("Version error: {0}")]
34    Version(#[from] VersionError),
35}
36
37/// Compatibility adapter for handling different protocol versions
38pub struct CompatibilityAdapter {
39    /// Version manager
40    version_manager: VersionManager,
41    /// Message transformers for different version pairs
42    transformers: HashMap<(ProtocolVersion, ProtocolVersion), Box<dyn MessageTransformer>>,
43    /// Feature compatibility matrix
44    feature_compatibility: HashMap<ProtocolVersion, Vec<String>>,
45}
46
47/// Message transformer trait
48pub trait MessageTransformer: Send + Sync {
49    /// Transform message from one version to another
50    fn transform(&self, message: &Message) -> Result<Message, CompatibilityError>;
51
52    /// Check if transformation is possible
53    fn can_transform(&self, message: &Message) -> bool;
54
55    /// Get transformation description
56    fn description(&self) -> &str;
57}
58
59/// Default message transformer (direct copy with version update)
60pub struct DirectTransformer {
61    from_version: ProtocolVersion,
62    to_version: ProtocolVersion,
63}
64
65/// Downgrade transformer (removes unsupported features)
66pub struct DowngradeTransformer {
67    from_version: ProtocolVersion,
68    to_version: ProtocolVersion,
69    removed_features: Vec<String>,
70}
71
72/// Upgrade transformer (adds default values for new features)
73pub struct UpgradeTransformer {
74    from_version: ProtocolVersion,
75    to_version: ProtocolVersion,
76    added_features: Vec<String>,
77}
78
79/// Legacy message format for version 1.0.0
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct LegacyMessage {
82    /// Message type (simplified)
83    pub msg_type: LegacyMessageType,
84    /// Message payload
85    pub payload: Vec<u8>,
86    /// Message timestamp
87    pub timestamp: u64,
88    /// Message signature
89    pub signature: Vec<u8>,
90}
91
92/// Legacy message types
93#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
94pub enum LegacyMessageType {
95    Handshake,
96    Data,
97    Control,
98    Sync,
99}
100
101impl CompatibilityAdapter {
102    /// Create a new compatibility adapter
103    pub fn new(version_manager: VersionManager) -> Self {
104        let mut adapter = Self {
105            version_manager,
106            transformers: HashMap::new(),
107            feature_compatibility: HashMap::new(),
108        };
109
110        adapter.setup_default_transformers();
111        adapter.setup_feature_compatibility();
112        adapter
113    }
114
115    /// Set up default message transformers
116    fn setup_default_transformers(&mut self) {
117        let v1_0_0 = ProtocolVersion {
118            major: 1,
119            minor: 0,
120            patch: 0,
121            features: vec![],
122        };
123        let v1_1_0 = ProtocolVersion {
124            major: 1,
125            minor: 1,
126            patch: 0,
127            features: vec![],
128        };
129
130        // Direct transformer for compatible versions
131        self.transformers.insert(
132            (v1_0_0.clone(), v1_1_0.clone()),
133            Box::new(UpgradeTransformer {
134                from_version: v1_0_0.clone(),
135                to_version: v1_1_0.clone(),
136                added_features: vec!["dark-addressing".to_string()],
137            }),
138        );
139
140        // Downgrade transformer
141        self.transformers.insert(
142            (v1_1_0.clone(), v1_0_0.clone()),
143            Box::new(DowngradeTransformer {
144                from_version: v1_1_0,
145                to_version: v1_0_0,
146                removed_features: vec!["dark-addressing".to_string()],
147            }),
148        );
149    }
150
151    /// Set up feature compatibility matrix
152    fn setup_feature_compatibility(&mut self) {
153        let v1_0_0 = ProtocolVersion {
154            major: 1,
155            minor: 0,
156            patch: 0,
157            features: vec![],
158        };
159        let v1_1_0 = ProtocolVersion {
160            major: 1,
161            minor: 1,
162            patch: 0,
163            features: vec![],
164        };
165
166        self.feature_compatibility.insert(
167            v1_0_0,
168            vec![
169                "basic-messaging".to_string(),
170                "quantum-resistant-crypto".to_string(),
171                "dag-consensus".to_string(),
172                "anonymous-routing".to_string(),
173            ],
174        );
175
176        self.feature_compatibility.insert(
177            v1_1_0,
178            vec![
179                "basic-messaging".to_string(),
180                "quantum-resistant-crypto".to_string(),
181                "dag-consensus".to_string(),
182                "anonymous-routing".to_string(),
183                "dark-addressing".to_string(),
184                "enhanced-privacy".to_string(),
185            ],
186        );
187    }
188
189    /// Transform message to target version
190    pub fn transform_message(
191        &self,
192        message: &Message,
193        target_version: &ProtocolVersion,
194    ) -> Result<Message, CompatibilityError> {
195        if &message.version == target_version {
196            return Ok(message.clone());
197        }
198
199        // Check if transformation is possible
200        if !self
201            .version_manager
202            .registry()
203            .are_compatible(&message.version, target_version)
204        {
205            return Err(CompatibilityError::VersionNotSupported {
206                version: target_version.clone(),
207            });
208        }
209
210        // Look for direct transformer
211        if let Some(transformer) = self
212            .transformers
213            .get(&(message.version.clone(), target_version.clone()))
214        {
215            return transformer.transform(message);
216        }
217
218        // Use version manager for migration
219        self.version_manager
220            .migrate_message(message, &message.version, target_version)
221            .map_err(CompatibilityError::Version)
222    }
223
224    /// Check if feature is available in version
225    pub fn is_feature_available(&self, version: &ProtocolVersion, feature: &str) -> bool {
226        self.feature_compatibility
227            .get(version)
228            .map(|features| features.contains(&feature.to_string()))
229            .unwrap_or(false)
230    }
231
232    /// Get supported features for version
233    pub fn get_supported_features(&self, version: &ProtocolVersion) -> Vec<String> {
234        self.feature_compatibility
235            .get(version)
236            .cloned()
237            .unwrap_or_default()
238    }
239
240    /// Convert modern message to legacy format
241    pub fn to_legacy_format(&self, message: &Message) -> Result<LegacyMessage, CompatibilityError> {
242        let legacy_type = match &message.msg_type {
243            MessageType::Handshake(_) => LegacyMessageType::Handshake,
244            MessageType::Control(_) => LegacyMessageType::Control,
245            MessageType::Sync(_) => LegacyMessageType::Sync,
246            _ => LegacyMessageType::Data,
247        };
248
249        Ok(LegacyMessage {
250            msg_type: legacy_type,
251            payload: message.payload.clone(),
252            timestamp: message.timestamp,
253            signature: message.signature.clone().unwrap_or_default(),
254        })
255    }
256
257    /// Convert legacy message to modern format
258    pub fn from_legacy_format(
259        &self,
260        legacy: &LegacyMessage,
261    ) -> Result<Message, CompatibilityError> {
262        use crate::message::{ControlMessageType, HandshakeType, SyncMessageType};
263
264        let msg_type = match legacy.msg_type {
265            LegacyMessageType::Handshake => MessageType::Handshake(HandshakeType::Init),
266            LegacyMessageType::Control => MessageType::Control(ControlMessageType::Ping),
267            LegacyMessageType::Sync => MessageType::Sync(SyncMessageType::StateRequest),
268            LegacyMessageType::Data => {
269                MessageType::Routing(crate::message::RoutingMessageType::Direct)
270            }
271        };
272
273        let mut message = Message::new(msg_type, legacy.payload.clone());
274        message.timestamp = legacy.timestamp;
275        if !legacy.signature.is_empty() {
276            message.signature = Some(legacy.signature.clone());
277        }
278
279        // Set version to 1.0.0 for legacy messages
280        message.version = ProtocolVersion {
281            major: 1,
282            minor: 0,
283            patch: 0,
284            features: vec![],
285        };
286
287        Ok(message)
288    }
289
290    /// Add custom transformer
291    pub fn add_transformer(
292        &mut self,
293        from_version: ProtocolVersion,
294        to_version: ProtocolVersion,
295        transformer: Box<dyn MessageTransformer>,
296    ) {
297        self.transformers
298            .insert((from_version, to_version), transformer);
299    }
300
301    /// Check compatibility between two versions
302    pub fn check_compatibility(
303        &self,
304        version1: &ProtocolVersion,
305        version2: &ProtocolVersion,
306    ) -> Result<Vec<String>, CompatibilityError> {
307        let mut compatibility_notes = Vec::new();
308
309        if version1 == version2 {
310            compatibility_notes.push("Versions are identical".to_string());
311            return Ok(compatibility_notes);
312        }
313
314        if !self
315            .version_manager
316            .registry()
317            .are_compatible(version1, version2)
318        {
319            return Err(CompatibilityError::VersionNotSupported {
320                version: version2.clone(),
321            });
322        }
323
324        // Check feature differences
325        let features1 = self.get_supported_features(version1);
326        let features2 = self.get_supported_features(version2);
327
328        let added_features: Vec<_> = features2
329            .iter()
330            .filter(|f| !features1.contains(f))
331            .cloned()
332            .collect();
333
334        let removed_features: Vec<_> = features1
335            .iter()
336            .filter(|f| !features2.contains(f))
337            .cloned()
338            .collect();
339
340        if !added_features.is_empty() {
341            compatibility_notes.push(format!("Added features: {}", added_features.join(", ")));
342        }
343
344        if !removed_features.is_empty() {
345            compatibility_notes.push(format!("Removed features: {}", removed_features.join(", ")));
346        }
347
348        if added_features.is_empty() && removed_features.is_empty() {
349            compatibility_notes.push("No feature differences".to_string());
350        }
351
352        Ok(compatibility_notes)
353    }
354}
355
356impl MessageTransformer for DirectTransformer {
357    fn transform(&self, message: &Message) -> Result<Message, CompatibilityError> {
358        let mut transformed = message.clone();
359        transformed.version = self.to_version.clone();
360        Ok(transformed)
361    }
362
363    fn can_transform(&self, message: &Message) -> bool {
364        message.version == self.from_version
365    }
366
367    fn description(&self) -> &str {
368        "Direct transformation with version update"
369    }
370}
371
372impl MessageTransformer for DowngradeTransformer {
373    fn transform(&self, message: &Message) -> Result<Message, CompatibilityError> {
374        let mut transformed = message.clone();
375        transformed.version = self.to_version.clone();
376
377        // Remove headers for unsupported features
378        for feature in &self.removed_features {
379            if feature.as_str() == "dark-addressing" {
380                transformed.headers.remove("dark-address");
381                transformed.headers.remove("shadow-route");
382            }
383        }
384
385        // Transform message types that are not supported in target version
386        if let MessageType::Anonymous(_) = &message.msg_type {
387            // Convert to direct routing for older versions
388            transformed.msg_type = MessageType::Routing(crate::message::RoutingMessageType::Direct);
389        }
390
391        Ok(transformed)
392    }
393
394    fn can_transform(&self, message: &Message) -> bool {
395        message.version == self.from_version
396    }
397
398    fn description(&self) -> &str {
399        "Downgrade transformation removing unsupported features"
400    }
401}
402
403impl MessageTransformer for UpgradeTransformer {
404    fn transform(&self, message: &Message) -> Result<Message, CompatibilityError> {
405        let mut transformed = message.clone();
406        transformed.version = self.to_version.clone();
407
408        // Add default values for new features
409        for feature in &self.added_features {
410            if feature.as_str() == "dark-addressing" {
411                // Add default dark addressing headers if not present
412                if !transformed.headers.contains_key("addressing-mode") {
413                    transformed
414                        .headers
415                        .insert("addressing-mode".to_string(), "standard".to_string());
416                }
417            }
418        }
419
420        Ok(transformed)
421    }
422
423    fn can_transform(&self, message: &Message) -> bool {
424        message.version == self.from_version
425    }
426
427    fn description(&self) -> &str {
428        "Upgrade transformation adding default values for new features"
429    }
430}
431
432#[cfg(test)]
433mod tests {
434    use super::*;
435    use crate::message::MessageFactory;
436    use crate::versioning::VersionManager;
437
438    #[test]
439    fn test_version_compatibility() {
440        let version_manager = VersionManager::new(ProtocolVersion {
441            major: 1,
442            minor: 1,
443            patch: 0,
444            features: vec![],
445        });
446        let adapter = CompatibilityAdapter::new(version_manager);
447
448        let v1_0_0 = ProtocolVersion {
449            major: 1,
450            minor: 0,
451            patch: 0,
452            features: vec![],
453        };
454        let v1_1_0 = ProtocolVersion {
455            major: 1,
456            minor: 1,
457            patch: 0,
458            features: vec![],
459        };
460
461        let notes = adapter.check_compatibility(&v1_0_0, &v1_1_0).unwrap();
462        assert!(!notes.is_empty());
463    }
464
465    #[test]
466    fn test_message_transformation() {
467        let version_manager = VersionManager::new(ProtocolVersion {
468            major: 1,
469            minor: 1,
470            patch: 0,
471            features: vec![],
472        });
473        let adapter = CompatibilityAdapter::new(version_manager);
474
475        let mut message = MessageFactory::create_ping().unwrap();
476        message.version = ProtocolVersion {
477            major: 1,
478            minor: 1,
479            patch: 0,
480            features: vec![],
481        };
482
483        let target_version = ProtocolVersion {
484            major: 1,
485            minor: 0,
486            patch: 0,
487            features: vec![],
488        };
489        let transformed = adapter
490            .transform_message(&message, &target_version)
491            .unwrap();
492
493        assert_eq!(transformed.version, target_version);
494    }
495
496    #[test]
497    fn test_legacy_conversion() {
498        let version_manager = VersionManager::new(ProtocolVersion {
499            major: 1,
500            minor: 0,
501            patch: 0,
502            features: vec![],
503        });
504        let adapter = CompatibilityAdapter::new(version_manager);
505
506        let message = MessageFactory::create_ping().unwrap();
507        let legacy = adapter.to_legacy_format(&message).unwrap();
508        let restored = adapter.from_legacy_format(&legacy).unwrap();
509
510        assert_eq!(message.payload, restored.payload);
511        assert_eq!(message.timestamp, restored.timestamp);
512    }
513}